Merge branch 'devel/master' into devel/graphics
[platform/core/uifw/dali-core.git] / dali / internal / render / common / render-algorithms.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-algorithms.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/internal/render/common/render-debug.h>
23 #include <dali/internal/render/common/render-instruction.h>
24 #include <dali/internal/render/common/render-list.h>
25 #include <dali/internal/render/renderers/render-renderer.h>
26 #include <dali/internal/update/nodes/scene-graph-layer.h>
27
28 using Dali::Internal::SceneGraph::RenderInstruction;
29 using Dali::Internal::SceneGraph::RenderItem;
30 using Dali::Internal::SceneGraph::RenderList;
31 using Dali::Internal::SceneGraph::RenderListContainer;
32
33 namespace Dali
34 {
35 namespace Internal
36 {
37 namespace Render
38 {
39 namespace
40 {
41 struct GraphicsDepthCompareOp
42 {
43   constexpr explicit GraphicsDepthCompareOp(DepthFunction::Type compareOp)
44   {
45     switch(compareOp)
46     {
47       case DepthFunction::NEVER:
48         op = Graphics::CompareOp::NEVER;
49         break;
50       case DepthFunction::LESS:
51         op = Graphics::CompareOp::LESS;
52         break;
53       case DepthFunction::EQUAL:
54         op = Graphics::CompareOp::EQUAL;
55         break;
56       case DepthFunction::LESS_EQUAL:
57         op = Graphics::CompareOp::LESS_OR_EQUAL;
58         break;
59       case DepthFunction::GREATER:
60         op = Graphics::CompareOp::GREATER;
61         break;
62       case DepthFunction::NOT_EQUAL:
63         op = Graphics::CompareOp::NOT_EQUAL;
64         break;
65       case DepthFunction::GREATER_EQUAL:
66         op = Graphics::CompareOp::GREATER_OR_EQUAL;
67         break;
68       case DepthFunction::ALWAYS:
69         op = Graphics::CompareOp::ALWAYS;
70         break;
71     }
72   }
73   Graphics::CompareOp op{Graphics::CompareOp::NEVER};
74 };
75
76 struct GraphicsStencilCompareOp
77 {
78   constexpr explicit GraphicsStencilCompareOp(StencilFunction::Type compareOp)
79   {
80     switch(compareOp)
81     {
82       case StencilFunction::NEVER:
83         op = Graphics::CompareOp::NEVER;
84         break;
85       case StencilFunction::LESS:
86         op = Graphics::CompareOp::LESS;
87         break;
88       case StencilFunction::EQUAL:
89         op = Graphics::CompareOp::EQUAL;
90         break;
91       case StencilFunction::LESS_EQUAL:
92         op = Graphics::CompareOp::LESS_OR_EQUAL;
93         break;
94       case StencilFunction::GREATER:
95         op = Graphics::CompareOp::GREATER;
96         break;
97       case StencilFunction::NOT_EQUAL:
98         op = Graphics::CompareOp::NOT_EQUAL;
99         break;
100       case StencilFunction::GREATER_EQUAL:
101         op = Graphics::CompareOp::GREATER_OR_EQUAL;
102         break;
103       case StencilFunction::ALWAYS:
104         op = Graphics::CompareOp::ALWAYS;
105         break;
106     }
107   }
108   Graphics::CompareOp op{Graphics::CompareOp::NEVER};
109 };
110
111 struct GraphicsStencilOp
112 {
113   constexpr explicit GraphicsStencilOp(StencilOperation::Type stencilOp)
114   {
115     switch(stencilOp)
116     {
117       case Dali::StencilOperation::KEEP:
118         op = Graphics::StencilOp::KEEP;
119         break;
120       case Dali::StencilOperation::ZERO:
121         op = Graphics::StencilOp::ZERO;
122         break;
123       case Dali::StencilOperation::REPLACE:
124         op = Graphics::StencilOp::REPLACE;
125         break;
126       case Dali::StencilOperation::INCREMENT:
127         op = Graphics::StencilOp::INCREMENT_AND_CLAMP;
128         break;
129       case Dali::StencilOperation::DECREMENT:
130         op = Graphics::StencilOp::DECREMENT_AND_CLAMP;
131         break;
132       case Dali::StencilOperation::INVERT:
133         op = Graphics::StencilOp::INVERT;
134         break;
135       case Dali::StencilOperation::INCREMENT_WRAP:
136         op = Graphics::StencilOp::INCREMENT_AND_WRAP;
137         break;
138       case Dali::StencilOperation::DECREMENT_WRAP:
139         op = Graphics::StencilOp::DECREMENT_AND_WRAP;
140         break;
141     }
142   }
143   Graphics::StencilOp op{Graphics::StencilOp::KEEP};
144 };
145
146 inline Graphics::Viewport ViewportFromClippingBox(ClippingBox clippingBox, int orientation)
147 {
148   Graphics::Viewport viewport{static_cast<float>(clippingBox.x), static_cast<float>(clippingBox.y), static_cast<float>(clippingBox.width), static_cast<float>(clippingBox.height), 0.0f, 0.0f};
149
150   if(orientation == 90 || orientation == 270)
151   {
152     viewport.width  = static_cast<float>(clippingBox.height);
153     viewport.height = static_cast<float>(clippingBox.width);
154   }
155   return viewport;
156 }
157
158 inline Graphics::Rect2D RecalculateRect(Graphics::Rect2D rect, int orientation, Graphics::Viewport viewport)
159 {
160   Graphics::Rect2D newRect;
161
162   // scissor's value should be set based on the default system coordinates.
163   // when the surface is rotated, the input valus already were set with the rotated angle.
164   // So, re-calculation is needed.
165   if(orientation == 90)
166   {
167     newRect.x      = viewport.height - (rect.y + rect.height);
168     newRect.y      = rect.x;
169     newRect.width  = rect.height;
170     newRect.height = rect.width;
171   }
172   else if(orientation == 180)
173   {
174     newRect.x      = viewport.width - (rect.x + rect.width);
175     newRect.y      = viewport.height - (rect.y + rect.height);
176     newRect.width  = rect.width;
177     newRect.height = rect.height;
178   }
179   else if(orientation == 270)
180   {
181     newRect.x      = rect.y;
182     newRect.y      = viewport.width - (rect.x + rect.width);
183     newRect.width  = rect.height;
184     newRect.height = rect.width;
185   }
186   else
187   {
188     newRect.x      = rect.x;
189     newRect.y      = rect.y;
190     newRect.width  = rect.width;
191     newRect.height = rect.height;
192   }
193   return newRect;
194 }
195
196 inline Graphics::Rect2D Rect2DFromClippingBox(ClippingBox clippingBox, int orientation, Graphics::Viewport viewport)
197 {
198   Graphics::Rect2D rect2D{clippingBox.x, clippingBox.y, static_cast<uint32_t>(abs(clippingBox.width)), static_cast<uint32_t>(abs(clippingBox.height))};
199   return RecalculateRect(rect2D, orientation, viewport);
200 }
201
202 inline Graphics::Rect2D Rect2DFromRect(Dali::Rect<int> rect, int orientation, Graphics::Viewport viewport)
203 {
204   Graphics::Rect2D rect2D{rect.x, rect.y, static_cast<uint32_t>(abs(rect.width)), static_cast<uint32_t>(abs(rect.height))};
205   return RecalculateRect(rect2D, orientation, viewport);
206 }
207
208 /**
209  * @brief Find the intersection of two AABB rectangles.
210  * This is a logical AND operation. IE. The intersection is the area overlapped by both rectangles.
211  * @param[in]     aabbA                  Rectangle A
212  * @param[in]     aabbB                  Rectangle B
213  * @return                               The intersection of rectangle A & B (result is a rectangle)
214  */
215 inline ClippingBox IntersectAABB(const ClippingBox& aabbA, const ClippingBox& aabbB)
216 {
217   ClippingBox intersectionBox;
218
219   // First calculate the largest starting positions in X and Y.
220   intersectionBox.x = std::max(aabbA.x, aabbB.x);
221   intersectionBox.y = std::max(aabbA.y, aabbB.y);
222
223   // Now calculate the smallest ending positions, and take the largest starting
224   // positions from the result, to get the width and height respectively.
225   // If the two boxes do not intersect at all, then we need a 0 width and height clipping area.
226   // We use max here to clamp both width and height to >= 0 for this use-case.
227   intersectionBox.width  = std::max(std::min(aabbA.x + aabbA.width, aabbB.x + aabbB.width) - intersectionBox.x, 0);
228   intersectionBox.height = std::max(std::min(aabbA.y + aabbA.height, aabbB.y + aabbB.height) - intersectionBox.y, 0);
229
230   return intersectionBox;
231 }
232
233 /**
234  * @brief Set up the stencil and color buffer for automatic clipping (StencilMode::AUTO).
235  * @param[in]     item                     The current RenderItem about to be rendered
236  * @param[in,out] commandBuffer            The command buffer to write stencil commands into
237  * @param[in,out] lastClippingDepth        The stencil depth of the last renderer drawn.
238  * @param[in,out] lastClippingId           The clipping ID of the last renderer drawn.
239  */
240 inline void SetupStencilClipping(const RenderItem& item, Graphics::CommandBuffer& commandBuffer, uint32_t& lastClippingDepth, uint32_t& lastClippingId)
241 {
242   const Dali::Internal::SceneGraph::Node* node       = item.mNode;
243   const uint32_t                          clippingId = node->GetClippingId();
244   // If there is no clipping Id, then either we haven't reached a clipping Node yet, or there aren't any.
245   // Either way we can skip clipping setup for this renderer.
246   if(clippingId == 0u)
247   {
248     // Exit immediately if there are no clipping actions to perform (EG. we have not yet hit a clipping node).
249     commandBuffer.SetStencilTestEnable(false);
250     return;
251   }
252   commandBuffer.SetStencilTestEnable(true);
253
254   const uint32_t clippingDepth = node->GetClippingDepth();
255
256   // Pre-calculate a mask which has all bits set up to and including the current clipping depth.
257   // EG. If depth is 3, the mask would be "111" in binary.
258   const uint32_t currentDepthMask = (1u << clippingDepth) - 1u;
259
260   // Are we are writing to the stencil buffer?
261   if(item.mNode->GetClippingMode() == Dali::ClippingMode::CLIP_CHILDREN)
262   {
263     // We are writing to the stencil buffer.
264     // If clipping Id is 1, this is the first clipping renderer within this render-list.
265     if(clippingId == 1u)
266     {
267       // We are enabling the stencil-buffer for the first time within this render list.
268       // Clear the buffer at this point.
269
270       commandBuffer.SetStencilWriteMask(0xFF);
271       commandBuffer.ClearStencilBuffer();
272     }
273     else if((clippingDepth < lastClippingDepth) ||
274             ((clippingDepth == lastClippingDepth) && (clippingId > lastClippingId)))
275     {
276       // The above if() statement tests if we need to clear some (not all) stencil bit-planes.
277       // We need to do this if either of the following are true:
278       //   1) We traverse up the scene-graph to a previous stencil depth
279       //   2) We are at the same stencil depth but the clipping Id has increased.
280       //
281       // This calculation takes the new depth to move to, and creates an inverse-mask of that number of consecutive bits.
282       // This has the effect of clearing everything except the bit-planes up to (and including) our current depth.
283       const uint32_t stencilClearMask = (currentDepthMask >> 1u) ^ 0xff;
284
285       commandBuffer.SetStencilWriteMask(stencilClearMask);
286       commandBuffer.ClearStencilBuffer();
287     }
288
289     // We keep track of the last clipping Id and depth so we can determine when we are
290     // moving back up the scene graph and require some of the stencil bit-planes to be deleted.
291     lastClippingDepth = clippingDepth;
292     lastClippingId    = clippingId;
293
294     // We only ever write to bit-planes up to the current depth as we may need
295     // to erase individual bit-planes and revert to a previous clipping area.
296     // Our reference value for testing (in StencilFunc) is written to to the buffer, but we actually
297     // want to test a different value. IE. All the bit-planes up to but not including the current depth.
298     // So we use the Mask parameter of StencilFunc to mask off the top bit-plane when testing.
299     // Here we create our test mask to innore the top bit of the reference test value.
300     // As the mask is made up of contiguous "1" values, we can do this quickly with a bit-shift.
301     const uint32_t testMask = currentDepthMask >> 1u;
302
303     // Test against existing stencil bit-planes. All must match up to (but not including) this depth.
304     commandBuffer.SetStencilFunc(Graphics::CompareOp::EQUAL, currentDepthMask, testMask);
305     // Write to the new stencil bit-plane (the other previous bit-planes are also written to).
306     commandBuffer.SetStencilWriteMask(currentDepthMask);
307     commandBuffer.SetStencilOp(Graphics::StencilOp::KEEP, Graphics::StencilOp::REPLACE, Graphics::StencilOp::REPLACE);
308   }
309   else
310   {
311     // We are reading from the stencil buffer. Set up the stencil accordingly
312     // This calculation sets all the bits up to the current depth bit.
313     // This has the effect of testing that the pixel being written to exists in every bit-plane up to the current depth.
314     commandBuffer.SetStencilFunc(Graphics::CompareOp::EQUAL, currentDepthMask, currentDepthMask);
315     commandBuffer.SetStencilOp(Graphics::StencilOp::KEEP, Graphics::StencilOp::KEEP, Graphics::StencilOp::KEEP);
316   }
317 }
318
319 /**
320  * @brief Sets up the depth buffer for reading and writing based on the current render item.
321  * The items read and write mode are used if specified.
322  *  - If AUTO is selected for reading, the decision will be based on the Layer Behavior.
323  *  - If AUTO is selected for writing, the decision will be based on the items opacity.
324  * @param[in]     item                The RenderItem to set up the depth buffer for.
325  * @param[in,out] secondaryCommandBuffer The secondary command buffer to write depth commands to
326  * @param[in]     depthTestEnabled    True if depth testing has been enabled.
327  * @param[in/out] firstDepthBufferUse Initialize to true on the first call, this method will set it to false afterwards.
328  */
329 inline void SetupDepthBuffer(const RenderItem& item, Graphics::CommandBuffer& commandBuffer, bool depthTestEnabled, bool& firstDepthBufferUse)
330 {
331   // Set up whether or not to write to the depth buffer.
332   const DepthWriteMode::Type depthWriteMode = item.mRenderer->GetDepthWriteMode();
333   // Most common mode (AUTO) is tested first.
334   const bool enableDepthWrite = ((depthWriteMode == DepthWriteMode::AUTO) && depthTestEnabled && item.mIsOpaque) ||
335                                 (depthWriteMode == DepthWriteMode::ON);
336
337   // Set up whether or not to read from (test) the depth buffer.
338   const DepthTestMode::Type depthTestMode = item.mRenderer->GetDepthTestMode();
339
340   // Most common mode (AUTO) is tested first.
341   const bool enableDepthTest = ((depthTestMode == DepthTestMode::AUTO) && depthTestEnabled) ||
342                                (depthTestMode == DepthTestMode::ON);
343
344   // Is the depth buffer in use?
345   if(enableDepthWrite || enableDepthTest)
346   {
347     // The depth buffer must be enabled if either reading or writing.
348     commandBuffer.SetDepthTestEnable(true);
349
350     // Look-up the depth function from the Dali::DepthFunction enum, and set it.
351     commandBuffer.SetDepthCompareOp(GraphicsDepthCompareOp(item.mRenderer->GetDepthFunction()).op);
352
353     // If this is the first use of the depth buffer this RenderTask, perform a clear.
354     // Note: We could do this at the beginning of the RenderTask and rely on the
355     // graphics implementation to ignore the clear if not required, but, we would
356     // have to enable the depth buffer to do so, which could be a redundant enable.
357     if(DALI_UNLIKELY(firstDepthBufferUse))
358     {
359       // This is the first time the depth buffer is being written to or read.
360       firstDepthBufferUse = false;
361
362       // Note: The buffer will only be cleared if written to since a previous clear.
363       commandBuffer.SetDepthWriteEnable(true);
364       commandBuffer.ClearDepthBuffer();
365     }
366
367     // Set up the depth mask based on our depth write setting.
368     commandBuffer.SetDepthWriteEnable(enableDepthWrite);
369   }
370   else
371   {
372     // The depth buffer is not being used by this renderer, so we must disable it to stop it being tested.
373     commandBuffer.SetDepthTestEnable(false);
374   }
375 }
376
377 } // Unnamed namespace
378
379 /**
380  * @brief This method is responsible for making decisions on when to apply and unapply scissor clipping, and what rectangular dimensions should be used.
381  * A stack of scissor clips at each depth of clipping is maintained, so it can be applied and unapplied.
382  * As the clips are hierarchical, this RenderItems AABB is clipped against the current "active" scissor bounds via an intersection operation.
383  * @param[in]     item                     The current RenderItem about to be rendered
384  * @param[in,out] commandBuffer            The command buffer to write into
385  * @param[in]     instruction              The render-instruction to process.
386  */
387 inline void RenderAlgorithms::SetupScissorClipping(
388   const RenderItem&        item,
389   Graphics::CommandBuffer& commandBuffer,
390   const RenderInstruction& instruction)
391 {
392   // Get the number of child scissors in the stack (do not include layer or root box).
393   size_t         childStackDepth = mScissorStack.size() - 1u;
394   const uint32_t scissorDepth    = item.mNode->GetScissorDepth();
395   const bool     clippingNode    = item.mNode->GetClippingMode() == Dali::ClippingMode::CLIP_TO_BOUNDING_BOX;
396   bool           traversedUpTree = false;
397
398   // If we are using scissor clipping and we are at the same depth (or less), we need to undo previous clips.
399   // We do this by traversing up the scissor clip stack and then apply the appropriate clip for the current render item.
400   // To know this, we use clippingDepth. This value is set on *every* node, but only increased as clipping nodes are hit depth-wise.
401   // So we know if we are at depth 4 and the stackDepth is 5, that we have gone up.
402   // If the depth is the same then we are effectively part of a different sub-tree from the parent, we must also remove the current clip.
403   // Note: Stack depth must always be at least 1, as we will have the layer or stage size as the root value.
404   if((childStackDepth > 0u) && (scissorDepth < childStackDepth))
405   {
406     while(scissorDepth < childStackDepth)
407     {
408       mScissorStack.pop_back();
409       --childStackDepth;
410     }
411
412     // We traversed up the tree, we need to apply a new scissor rectangle (unless we are at the root).
413     traversedUpTree = true;
414   }
415   if(clippingNode && childStackDepth > 0u && childStackDepth == scissorDepth) // case of sibling clip area
416   {
417     mScissorStack.pop_back();
418     --childStackDepth;
419   }
420
421   // If we are on a clipping node, or we have traveled up the tree and gone back past a clipping node, may need to apply a new scissor clip.
422   if(clippingNode || traversedUpTree)
423   {
424     // First, check if we are a clipping node.
425     if(clippingNode)
426     {
427       // This is a clipping node. We generate the AABB for this node and intersect it with the previous intersection further up the tree.
428
429       // Get the AABB bounding box for the current render item.
430       const ClippingBox scissorBox(item.CalculateViewportSpaceAABB(item.mSize, mViewportRectangle.width, mViewportRectangle.height));
431
432       // Get the AABB for the parent item that we must intersect with.
433       const ClippingBox& parentBox(mScissorStack.back());
434
435       // We must reduce the clipping area based on the parents area to allow nested clips. This is a set intersection function.
436       // We add the new scissor box to the stack so we can return to it if needed.
437       mScissorStack.emplace_back(IntersectAABB(parentBox, scissorBox));
438     }
439
440     // The scissor test is enabled if we have any children on the stack, OR, if there are none but it is a user specified layer scissor box.
441     // IE. It is not enabled if we are at the top of the stack and the layer does not have a specified clipping box.
442     const bool scissorEnabled = (!mScissorStack.empty()) || mHasLayerScissor;
443
444     // Enable the scissor test based on the above calculation
445     if(scissorEnabled)
446     {
447       commandBuffer.SetScissorTestEnable(scissorEnabled);
448     }
449
450     // If scissor is enabled, we use the calculated screen-space coordinates (now in the stack).
451     if(scissorEnabled)
452     {
453       ClippingBox useScissorBox(mScissorStack.back());
454
455       if(instruction.mFrameBuffer && instruction.GetCamera()->IsYAxisInverted())
456       {
457         useScissorBox.y = (instruction.mFrameBuffer->GetHeight() - useScissorBox.height) - useScissorBox.y;
458       }
459       Graphics::Rect2D scissorBox = {useScissorBox.x, useScissorBox.y, uint32_t(useScissorBox.width), uint32_t(useScissorBox.height)};
460       commandBuffer.SetScissor(scissorBox);
461     }
462   }
463 }
464
465 inline void RenderAlgorithms::SetupClipping(const RenderItem&                   item,
466                                             Graphics::CommandBuffer&            commandBuffer,
467                                             bool&                               usedStencilBuffer,
468                                             uint32_t&                           lastClippingDepth,
469                                             uint32_t&                           lastClippingId,
470                                             Integration::StencilBufferAvailable stencilBufferAvailable,
471                                             const RenderInstruction&            instruction)
472 {
473   RenderMode::Type renderMode = RenderMode::AUTO;
474   const Renderer*  renderer   = item.mRenderer;
475   if(renderer)
476   {
477     renderMode = renderer->GetRenderMode();
478   }
479
480   // Setup the stencil using either the automatic clipping feature, or, the manual per-renderer stencil API.
481   // Note: This switch is in order of most likely value first.
482   switch(renderMode)
483   {
484     case RenderMode::AUTO:
485     {
486       // Turn the color buffer on as we always want to render this renderer, regardless of clipping hierarchy.
487       commandBuffer.SetColorMask(true);
488
489       // The automatic clipping feature will manage the scissor and stencil functions, only if stencil buffer is available for the latter.
490       // As both scissor and stencil clips can be nested, we may be simultaneously traversing up the scissor tree, requiring a scissor to be un-done. Whilst simultaneously adding a new stencil clip.
491       // We process both based on our current and old clipping depths for each mode.
492       // Both methods with return rapidly if there is nothing to be done for that type of clipping.
493       SetupScissorClipping(item, commandBuffer, instruction);
494
495       if(stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
496       {
497         SetupStencilClipping(item, commandBuffer, lastClippingDepth, lastClippingId);
498       }
499       break;
500     }
501
502     case RenderMode::NONE:
503     case RenderMode::COLOR:
504     {
505       // No clipping is performed for these modes.
506       // Note: We do not turn off scissor clipping as it may be used for the whole layer.
507       // The stencil buffer will not be used at all, but we only need to disable it if it's available.
508       if(stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
509       {
510         commandBuffer.SetStencilTestEnable(false);
511       }
512
513       // Setup the color buffer based on the RenderMode.
514       commandBuffer.SetColorMask(renderMode == RenderMode::COLOR);
515       break;
516     }
517
518     case RenderMode::STENCIL:
519     case RenderMode::COLOR_STENCIL:
520     {
521       if(stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
522       {
523         // We are using the low-level Renderer Stencil API.
524         // The stencil buffer must be enabled for every renderer with stencil mode on, as renderers in between can disable it.
525         // Note: As the command state is cached, it is only sent when needed.
526         commandBuffer.SetStencilTestEnable(true);
527
528         // Setup the color buffer based on the RenderMode.
529         commandBuffer.SetColorMask(renderMode == RenderMode::COLOR_STENCIL);
530
531         // If this is the first use of the stencil buffer within this RenderList, clear it (this avoids unnecessary clears).
532         if(!usedStencilBuffer)
533         {
534           commandBuffer.ClearStencilBuffer();
535           usedStencilBuffer = true;
536         }
537
538         // Setup the stencil buffer based on the renderer's properties.
539         commandBuffer.SetStencilOp(GraphicsStencilOp(renderer->GetStencilOperationOnFail()).op,
540                                    GraphicsStencilOp(renderer->GetStencilOperationOnZPass()).op,
541                                    GraphicsStencilOp(renderer->GetStencilOperationOnZFail()).op);
542         commandBuffer.SetStencilFunc(GraphicsStencilCompareOp(renderer->GetStencilFunction()).op,
543                                      renderer->GetStencilFunctionReference(),
544                                      renderer->GetStencilFunctionMask());
545         commandBuffer.SetStencilWriteMask(renderer->GetStencilMask());
546       }
547       break;
548     }
549   }
550 }
551
552 inline void RenderAlgorithms::ProcessRenderList(const RenderList&                   renderList,
553                                                 BufferIndex                         bufferIndex,
554                                                 const Matrix&                       viewMatrix,
555                                                 const Matrix&                       projectionMatrix,
556                                                 Integration::DepthBufferAvailable   depthBufferAvailable,
557                                                 Integration::StencilBufferAvailable stencilBufferAvailable,
558                                                 Vector<Graphics::Texture*>&         boundTextures,
559                                                 const RenderInstruction&            instruction,
560                                                 const Rect<int32_t>&                viewport,
561                                                 const Rect<int>&                    rootClippingRect,
562                                                 int                                 orientation)
563 {
564   DALI_PRINT_RENDER_LIST(renderList);
565
566   // Note: The depth buffer is enabled or disabled on a per-renderer basis.
567   // Here we pre-calculate the value to use if these modes are set to AUTO.
568   const bool        autoDepthTestMode((depthBufferAvailable == Integration::DepthBufferAvailable::TRUE) &&
569                                !(renderList.GetSourceLayer()->IsDepthTestDisabled()) &&
570                                renderList.HasColorRenderItems());
571   const std::size_t count = renderList.Count();
572   uint32_t          lastClippingDepth(0u);
573   uint32_t          lastClippingId(0u);
574   bool              usedStencilBuffer(false);
575   bool              firstDepthBufferUse(true);
576
577   mViewportRectangle = viewport;
578
579   auto* mutableRenderList      = const_cast<RenderList*>(&renderList);
580   auto& secondaryCommandBuffer = mutableRenderList->GetCommandBuffer(mGraphicsController);
581   secondaryCommandBuffer.Reset();
582
583   secondaryCommandBuffer.SetViewport(ViewportFromClippingBox(mViewportRectangle, orientation));
584   mHasLayerScissor = false;
585
586   // Setup Scissor testing (for both viewport and per-node scissor)
587   mScissorStack.clear();
588
589   // Add root clipping rect (set manually for Render function by partial update for example)
590   // on the bottom of the stack
591   if(!rootClippingRect.IsEmpty())
592   {
593     Graphics::Viewport graphicsViewport = ViewportFromClippingBox(mViewportRectangle, 0);
594     secondaryCommandBuffer.SetScissorTestEnable(true);
595     secondaryCommandBuffer.SetScissor(Rect2DFromRect(rootClippingRect, orientation, graphicsViewport));
596     mScissorStack.push_back(rootClippingRect);
597   }
598   // We are not performing a layer clip and no clipping rect set. Add the viewport as the root scissor rectangle.
599   else if(!renderList.IsClipping())
600   {
601     secondaryCommandBuffer.SetScissorTestEnable(false);
602     mScissorStack.push_back(mViewportRectangle);
603   }
604
605   if(renderList.IsClipping())
606   {
607     Graphics::Viewport graphicsViewport = ViewportFromClippingBox(mViewportRectangle, 0);
608     secondaryCommandBuffer.SetScissorTestEnable(true);
609     const ClippingBox& layerScissorBox = renderList.GetClippingBox();
610     secondaryCommandBuffer.SetScissor(Rect2DFromClippingBox(layerScissorBox, orientation, graphicsViewport));
611     mScissorStack.push_back(layerScissorBox);
612     mHasLayerScissor = true;
613   }
614
615   // Loop through all RenderItems in the RenderList, set up any prerequisites to render them, then perform the render.
616   for(uint32_t index = 0u; index < count; ++index)
617   {
618     const RenderItem& item = renderList.GetItem(index);
619
620     // Discard renderers outside the root clipping rect
621     bool skip = true;
622     if(!rootClippingRect.IsEmpty())
623     {
624       auto rect = item.CalculateViewportSpaceAABB(item.mUpdateSize, mViewportRectangle.width, mViewportRectangle.height);
625
626       if(rect.Intersect(rootClippingRect))
627       {
628         skip = false;
629       }
630     }
631     else
632     {
633       skip = false;
634     }
635
636     DALI_PRINT_RENDER_ITEM(item);
637
638     // Set up clipping based on both the Renderer and Actor APIs.
639     // The Renderer API will be used if specified. If AUTO, the Actors automatic clipping feature will be used.
640     SetupClipping(item, secondaryCommandBuffer, usedStencilBuffer, lastClippingDepth, lastClippingId, stencilBufferAvailable, instruction);
641
642     if(DALI_LIKELY(item.mRenderer))
643     {
644       // Set up the depth buffer based on per-renderer flags if depth buffer is available
645       // If the per renderer flags are set to "ON" or "OFF", they will always override any Layer depth mode or
646       // draw-mode state, such as Overlays.
647       // If the flags are set to "AUTO", the behavior then depends on the type of renderer. Overlay Renderers will
648       // always disable depth testing and writing. Color Renderers will enable them if the Layer does.
649       if(depthBufferAvailable == Integration::DepthBufferAvailable::TRUE)
650       {
651         SetupDepthBuffer(item, secondaryCommandBuffer, autoDepthTestMode, firstDepthBufferUse);
652       }
653
654       // Depending on whether the renderer has draw commands attached or not the rendering process will
655       // iterate through all the render queues. If there are no draw commands attached, only one
656       // iteration must be done and the default behaviour of the renderer will be executed.
657       // The queues allow to iterate over the same renderer multiple times changing the state of the renderer.
658       // It is similar to the multi-pass rendering.
659       if(!skip)
660       {
661         auto const MAX_QUEUE = item.mRenderer->GetDrawCommands().empty() ? 1 : DevelRenderer::RENDER_QUEUE_MAX;
662         for(auto queue = 0u; queue < MAX_QUEUE; ++queue)
663         {
664           // Render the item. It will write into the command buffer everything it has to render
665           item.mRenderer->Render(secondaryCommandBuffer, bufferIndex, *item.mNode, item.mModelMatrix, item.mModelViewMatrix, viewMatrix, projectionMatrix, item.mSize, !item.mIsOpaque, boundTextures, instruction, queue);
666         }
667       }
668     }
669   }
670 }
671
672 RenderAlgorithms::RenderAlgorithms(Graphics::Controller& graphicsController)
673 : mGraphicsController(graphicsController),
674   mViewportRectangle(),
675   mHasLayerScissor(false)
676 {
677 }
678
679 void RenderAlgorithms::ResetCommandBuffer()
680 {
681   // Reset main command buffer
682   if(!mGraphicsCommandBuffer)
683   {
684     mGraphicsCommandBuffer = mGraphicsController.CreateCommandBuffer(
685       Graphics::CommandBufferCreateInfo()
686         .SetLevel(Graphics::CommandBufferLevel::PRIMARY),
687       nullptr);
688   }
689   else
690   {
691     mGraphicsCommandBuffer->Reset();
692   }
693 }
694
695 void RenderAlgorithms::SubmitCommandBuffer()
696 {
697   // Submit main command buffer
698   Graphics::SubmitInfo submitInfo;
699   submitInfo.cmdBuffer.push_back(mGraphicsCommandBuffer.get());
700   submitInfo.flags = 0 | Graphics::SubmitFlagBits::FLUSH;
701   mGraphicsController.SubmitCommandBuffers(submitInfo);
702 }
703
704 void RenderAlgorithms::ProcessRenderInstruction(const RenderInstruction&            instruction,
705                                                 BufferIndex                         bufferIndex,
706                                                 Integration::DepthBufferAvailable   depthBufferAvailable,
707                                                 Integration::StencilBufferAvailable stencilBufferAvailable,
708                                                 Vector<Graphics::Texture*>&         boundTextures,
709                                                 const Rect<int32_t>&                viewport,
710                                                 const Rect<int>&                    rootClippingRect,
711                                                 int                                 orientation)
712 {
713   DALI_PRINT_RENDER_INSTRUCTION(instruction, bufferIndex);
714
715   const Matrix* viewMatrix       = instruction.GetViewMatrix(bufferIndex);
716   const Matrix* projectionMatrix = instruction.GetProjectionMatrix(bufferIndex);
717
718   DALI_ASSERT_DEBUG(viewMatrix);
719   DALI_ASSERT_DEBUG(projectionMatrix);
720
721   if(viewMatrix && projectionMatrix)
722   {
723     std::vector<const Graphics::CommandBuffer*> buffers;
724     const RenderListContainer::SizeType         count = instruction.RenderListCount();
725
726     // Iterate through each render list in order. If a pair of render lists
727     // are marked as interleaved, then process them together.
728     for(RenderListContainer::SizeType index = 0; index < count; ++index)
729     {
730       const RenderList* renderList = instruction.GetRenderList(index);
731
732       if(renderList && !renderList->IsEmpty())
733       {
734         ProcessRenderList(*renderList,
735                           bufferIndex,
736                           *viewMatrix,
737                           *projectionMatrix,
738                           depthBufferAvailable,
739                           stencilBufferAvailable,
740                           boundTextures,
741                           instruction, //added for reflection effect
742                           viewport,
743                           rootClippingRect,
744                           orientation);
745
746         // Execute command buffer
747         auto* commandBuffer = renderList->GetCommandBuffer();
748         if(commandBuffer)
749         {
750           buffers.push_back(commandBuffer);
751         }
752       }
753     }
754     if(!buffers.empty())
755     {
756       mGraphicsCommandBuffer->ExecuteCommandBuffers(std::move(buffers));
757     }
758   }
759 }
760
761 } // namespace Render
762
763 } // namespace Internal
764
765 } // namespace Dali