2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/render/common/render-algorithms.h>
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>
28 using Dali::Internal::SceneGraph::RenderInstruction;
29 using Dali::Internal::SceneGraph::RenderItem;
30 using Dali::Internal::SceneGraph::RenderList;
31 using Dali::Internal::SceneGraph::RenderListContainer;
41 struct GraphicsDepthCompareOp
43 constexpr explicit GraphicsDepthCompareOp(DepthFunction::Type compareOp)
47 case DepthFunction::NEVER:
48 op = Graphics::CompareOp::NEVER;
50 case DepthFunction::LESS:
51 op = Graphics::CompareOp::LESS;
53 case DepthFunction::EQUAL:
54 op = Graphics::CompareOp::EQUAL;
56 case DepthFunction::LESS_EQUAL:
57 op = Graphics::CompareOp::LESS_OR_EQUAL;
59 case DepthFunction::GREATER:
60 op = Graphics::CompareOp::GREATER;
62 case DepthFunction::NOT_EQUAL:
63 op = Graphics::CompareOp::NOT_EQUAL;
65 case DepthFunction::GREATER_EQUAL:
66 op = Graphics::CompareOp::GREATER_OR_EQUAL;
68 case DepthFunction::ALWAYS:
69 op = Graphics::CompareOp::ALWAYS;
73 Graphics::CompareOp op{Graphics::CompareOp::NEVER};
76 struct GraphicsStencilCompareOp
78 constexpr explicit GraphicsStencilCompareOp(StencilFunction::Type compareOp)
82 case StencilFunction::NEVER:
83 op = Graphics::CompareOp::NEVER;
85 case StencilFunction::LESS:
86 op = Graphics::CompareOp::LESS;
88 case StencilFunction::EQUAL:
89 op = Graphics::CompareOp::EQUAL;
91 case StencilFunction::LESS_EQUAL:
92 op = Graphics::CompareOp::LESS_OR_EQUAL;
94 case StencilFunction::GREATER:
95 op = Graphics::CompareOp::GREATER;
97 case StencilFunction::NOT_EQUAL:
98 op = Graphics::CompareOp::NOT_EQUAL;
100 case StencilFunction::GREATER_EQUAL:
101 op = Graphics::CompareOp::GREATER_OR_EQUAL;
103 case StencilFunction::ALWAYS:
104 op = Graphics::CompareOp::ALWAYS;
108 Graphics::CompareOp op{Graphics::CompareOp::NEVER};
111 struct GraphicsStencilOp
113 constexpr explicit GraphicsStencilOp(StencilOperation::Type stencilOp)
117 case Dali::StencilOperation::KEEP:
118 op = Graphics::StencilOp::KEEP;
120 case Dali::StencilOperation::ZERO:
121 op = Graphics::StencilOp::ZERO;
123 case Dali::StencilOperation::REPLACE:
124 op = Graphics::StencilOp::REPLACE;
126 case Dali::StencilOperation::INCREMENT:
127 op = Graphics::StencilOp::INCREMENT_AND_CLAMP;
129 case Dali::StencilOperation::DECREMENT:
130 op = Graphics::StencilOp::DECREMENT_AND_CLAMP;
132 case Dali::StencilOperation::INVERT:
133 op = Graphics::StencilOp::INVERT;
135 case Dali::StencilOperation::INCREMENT_WRAP:
136 op = Graphics::StencilOp::INCREMENT_AND_WRAP;
138 case Dali::StencilOperation::DECREMENT_WRAP:
139 op = Graphics::StencilOp::DECREMENT_AND_WRAP;
143 Graphics::StencilOp op{Graphics::StencilOp::KEEP};
146 inline Graphics::Viewport ViewportFromClippingBox(ClippingBox clippingBox, int orientation)
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};
150 if(orientation == 90 || orientation == 270)
152 viewport.width = static_cast<float>(clippingBox.height);
153 viewport.height = static_cast<float>(clippingBox.width);
158 inline Graphics::Rect2D RecalculateRect(Graphics::Rect2D rect, int orientation, Graphics::Viewport viewport)
160 Graphics::Rect2D newRect;
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)
167 newRect.x = viewport.height - (rect.y + rect.height);
169 newRect.width = rect.height;
170 newRect.height = rect.width;
172 else if(orientation == 180)
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;
179 else if(orientation == 270)
182 newRect.y = viewport.width - (rect.x + rect.width);
183 newRect.width = rect.height;
184 newRect.height = rect.width;
190 newRect.width = rect.width;
191 newRect.height = rect.height;
196 inline Graphics::Rect2D Rect2DFromClippingBox(ClippingBox clippingBox, int orientation, Graphics::Viewport viewport)
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);
202 inline Graphics::Rect2D Rect2DFromRect(Dali::Rect<int> rect, int orientation, Graphics::Viewport viewport)
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);
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)
215 inline ClippingBox IntersectAABB(const ClippingBox& aabbA, const ClippingBox& aabbB)
217 ClippingBox intersectionBox;
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);
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);
230 return intersectionBox;
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.
240 inline void SetupStencilClipping(const RenderItem& item, Graphics::CommandBuffer& commandBuffer, uint32_t& lastClippingDepth, uint32_t& lastClippingId)
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.
248 // Exit immediately if there are no clipping actions to perform (EG. we have not yet hit a clipping node).
249 commandBuffer.SetStencilTestEnable(false);
252 commandBuffer.SetStencilTestEnable(true);
254 const uint32_t clippingDepth = node->GetClippingDepth();
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;
260 // Are we are writing to the stencil buffer?
261 if(item.mNode->GetClippingMode() == Dali::ClippingMode::CLIP_CHILDREN)
263 // We are writing to the stencil buffer.
264 // If clipping Id is 1, this is the first clipping renderer within this render-list.
267 // We are enabling the stencil-buffer for the first time within this render list.
268 // Clear the buffer at this point.
270 commandBuffer.SetStencilWriteMask(0xFF);
271 commandBuffer.ClearStencilBuffer();
273 else if((clippingDepth < lastClippingDepth) ||
274 ((clippingDepth == lastClippingDepth) && (clippingId > lastClippingId)))
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.
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;
285 commandBuffer.SetStencilWriteMask(stencilClearMask);
286 commandBuffer.ClearStencilBuffer();
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;
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;
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);
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);
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.
329 inline void SetupDepthBuffer(const RenderItem& item, Graphics::CommandBuffer& commandBuffer, bool depthTestEnabled, bool& firstDepthBufferUse)
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);
337 // Set up whether or not to read from (test) the depth buffer.
338 const DepthTestMode::Type depthTestMode = item.mRenderer->GetDepthTestMode();
340 // Most common mode (AUTO) is tested first.
341 const bool enableDepthTest = ((depthTestMode == DepthTestMode::AUTO) && depthTestEnabled) ||
342 (depthTestMode == DepthTestMode::ON);
344 // Is the depth buffer in use?
345 if(enableDepthWrite || enableDepthTest)
347 // The depth buffer must be enabled if either reading or writing.
348 commandBuffer.SetDepthTestEnable(true);
350 // Look-up the depth function from the Dali::DepthFunction enum, and set it.
351 commandBuffer.SetDepthCompareOp(GraphicsDepthCompareOp(item.mRenderer->GetDepthFunction()).op);
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))
359 // This is the first time the depth buffer is being written to or read.
360 firstDepthBufferUse = false;
362 // Note: The buffer will only be cleared if written to since a previous clear.
363 commandBuffer.SetDepthWriteEnable(true);
364 commandBuffer.ClearDepthBuffer();
367 // Set up the depth mask based on our depth write setting.
368 commandBuffer.SetDepthWriteEnable(enableDepthWrite);
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);
377 } // Unnamed namespace
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 * @param[in] orientation The Scene's surface orientation.
388 inline void RenderAlgorithms::SetupScissorClipping(
389 const RenderItem& item,
390 Graphics::CommandBuffer& commandBuffer,
391 const RenderInstruction& instruction,
394 // Get the number of child scissors in the stack (do not include layer or root box).
395 size_t childStackDepth = mScissorStack.size() - 1u;
396 const uint32_t scissorDepth = item.mNode->GetScissorDepth();
397 const bool clippingNode = item.mNode->GetClippingMode() == Dali::ClippingMode::CLIP_TO_BOUNDING_BOX;
398 bool traversedUpTree = false;
400 // If we are using scissor clipping and we are at the same depth (or less), we need to undo previous clips.
401 // We do this by traversing up the scissor clip stack and then apply the appropriate clip for the current render item.
402 // To know this, we use clippingDepth. This value is set on *every* node, but only increased as clipping nodes are hit depth-wise.
403 // So we know if we are at depth 4 and the stackDepth is 5, that we have gone up.
404 // 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.
405 // Note: Stack depth must always be at least 1, as we will have the layer or stage size as the root value.
406 if((childStackDepth > 0u) && (scissorDepth < childStackDepth))
408 while(scissorDepth < childStackDepth)
410 mScissorStack.pop_back();
414 // We traversed up the tree, we need to apply a new scissor rectangle (unless we are at the root).
415 traversedUpTree = true;
417 if(clippingNode && childStackDepth > 0u && childStackDepth == scissorDepth) // case of sibling clip area
419 mScissorStack.pop_back();
423 // 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.
424 if(clippingNode || traversedUpTree)
426 // First, check if we are a clipping node.
429 // This is a clipping node. We generate the AABB for this node and intersect it with the previous intersection further up the tree.
431 // Get the AABB bounding box for the current render item.
432 const ClippingBox scissorBox(item.CalculateViewportSpaceAABB(item.mSize, mViewportRectangle.width, mViewportRectangle.height));
434 // Get the AABB for the parent item that we must intersect with.
435 const ClippingBox& parentBox(mScissorStack.back());
437 // We must reduce the clipping area based on the parents area to allow nested clips. This is a set intersection function.
438 // We add the new scissor box to the stack so we can return to it if needed.
439 mScissorStack.emplace_back(IntersectAABB(parentBox, scissorBox));
442 // 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.
443 // IE. It is not enabled if we are at the top of the stack and the layer does not have a specified clipping box.
444 const bool scissorEnabled = (!mScissorStack.empty()) || mHasLayerScissor;
446 // Enable the scissor test based on the above calculation
449 commandBuffer.SetScissorTestEnable(scissorEnabled);
452 // If scissor is enabled, we use the calculated screen-space coordinates (now in the stack).
455 ClippingBox useScissorBox(mScissorStack.back());
457 if(instruction.mFrameBuffer && instruction.GetCamera()->IsYAxisInverted())
459 useScissorBox.y = (instruction.mFrameBuffer->GetHeight() - useScissorBox.height) - useScissorBox.y;
462 Graphics::Viewport graphicsViewport = ViewportFromClippingBox(mViewportRectangle, 0);
463 commandBuffer.SetScissor(Rect2DFromClippingBox(useScissorBox, orientation, graphicsViewport));
468 inline void RenderAlgorithms::SetupClipping(const RenderItem& item,
469 Graphics::CommandBuffer& commandBuffer,
470 bool& usedStencilBuffer,
471 uint32_t& lastClippingDepth,
472 uint32_t& lastClippingId,
473 Integration::StencilBufferAvailable stencilBufferAvailable,
474 const RenderInstruction& instruction,
477 RenderMode::Type renderMode = RenderMode::AUTO;
478 const Renderer* renderer = item.mRenderer;
481 renderMode = renderer->GetRenderMode();
484 // Setup the stencil using either the automatic clipping feature, or, the manual per-renderer stencil API.
485 // Note: This switch is in order of most likely value first.
488 case RenderMode::AUTO:
490 // Turn the color buffer on as we always want to render this renderer, regardless of clipping hierarchy.
491 commandBuffer.SetColorMask(true);
493 // The automatic clipping feature will manage the scissor and stencil functions, only if stencil buffer is available for the latter.
494 // 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.
495 // We process both based on our current and old clipping depths for each mode.
496 // Both methods with return rapidly if there is nothing to be done for that type of clipping.
497 SetupScissorClipping(item, commandBuffer, instruction, orientation);
499 if(stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
501 SetupStencilClipping(item, commandBuffer, lastClippingDepth, lastClippingId);
506 case RenderMode::NONE:
507 case RenderMode::COLOR:
509 // No clipping is performed for these modes.
510 // Note: We do not turn off scissor clipping as it may be used for the whole layer.
511 // The stencil buffer will not be used at all, but we only need to disable it if it's available.
512 if(stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
514 commandBuffer.SetStencilTestEnable(false);
517 // Setup the color buffer based on the RenderMode.
518 commandBuffer.SetColorMask(renderMode == RenderMode::COLOR);
522 case RenderMode::STENCIL:
523 case RenderMode::COLOR_STENCIL:
525 if(stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
527 // We are using the low-level Renderer Stencil API.
528 // The stencil buffer must be enabled for every renderer with stencil mode on, as renderers in between can disable it.
529 // Note: As the command state is cached, it is only sent when needed.
530 commandBuffer.SetStencilTestEnable(true);
532 // Setup the color buffer based on the RenderMode.
533 commandBuffer.SetColorMask(renderMode == RenderMode::COLOR_STENCIL);
535 // If this is the first use of the stencil buffer within this RenderList, clear it (this avoids unnecessary clears).
536 if(!usedStencilBuffer)
538 commandBuffer.ClearStencilBuffer();
539 usedStencilBuffer = true;
542 // Setup the stencil buffer based on the renderer's properties.
543 commandBuffer.SetStencilOp(GraphicsStencilOp(renderer->GetStencilOperationOnFail()).op,
544 GraphicsStencilOp(renderer->GetStencilOperationOnZPass()).op,
545 GraphicsStencilOp(renderer->GetStencilOperationOnZFail()).op);
546 commandBuffer.SetStencilFunc(GraphicsStencilCompareOp(renderer->GetStencilFunction()).op,
547 renderer->GetStencilFunctionReference(),
548 renderer->GetStencilFunctionMask());
549 commandBuffer.SetStencilWriteMask(renderer->GetStencilMask());
556 inline void RenderAlgorithms::ProcessRenderList(const RenderList& renderList,
557 BufferIndex bufferIndex,
558 const Matrix& viewMatrix,
559 const Matrix& projectionMatrix,
560 Integration::DepthBufferAvailable depthBufferAvailable,
561 Integration::StencilBufferAvailable stencilBufferAvailable,
562 Vector<Graphics::Texture*>& boundTextures,
563 const RenderInstruction& instruction,
564 const Rect<int32_t>& viewport,
565 const Rect<int>& rootClippingRect,
568 DALI_PRINT_RENDER_LIST(renderList);
570 // Note: The depth buffer is enabled or disabled on a per-renderer basis.
571 // Here we pre-calculate the value to use if these modes are set to AUTO.
572 const bool autoDepthTestMode((depthBufferAvailable == Integration::DepthBufferAvailable::TRUE) &&
573 !(renderList.GetSourceLayer()->IsDepthTestDisabled()) &&
574 renderList.HasColorRenderItems());
575 const std::size_t count = renderList.Count();
576 uint32_t lastClippingDepth(0u);
577 uint32_t lastClippingId(0u);
578 bool usedStencilBuffer(false);
579 bool firstDepthBufferUse(true);
581 mViewportRectangle = viewport;
583 auto* mutableRenderList = const_cast<RenderList*>(&renderList);
584 auto& secondaryCommandBuffer = mutableRenderList->GetCommandBuffer(mGraphicsController);
585 secondaryCommandBuffer.Reset();
587 secondaryCommandBuffer.SetViewport(ViewportFromClippingBox(mViewportRectangle, orientation));
588 mHasLayerScissor = false;
590 // Setup Scissor testing (for both viewport and per-node scissor)
591 mScissorStack.clear();
593 // Add root clipping rect (set manually for Render function by partial update for example)
594 // on the bottom of the stack
595 if(!rootClippingRect.IsEmpty())
597 Graphics::Viewport graphicsViewport = ViewportFromClippingBox(mViewportRectangle, 0);
598 secondaryCommandBuffer.SetScissorTestEnable(true);
599 secondaryCommandBuffer.SetScissor(Rect2DFromRect(rootClippingRect, orientation, graphicsViewport));
600 mScissorStack.push_back(rootClippingRect);
602 // We are not performing a layer clip and no clipping rect set. Add the viewport as the root scissor rectangle.
603 else if(!renderList.IsClipping())
605 secondaryCommandBuffer.SetScissorTestEnable(false);
606 mScissorStack.push_back(mViewportRectangle);
609 if(renderList.IsClipping())
611 Graphics::Viewport graphicsViewport = ViewportFromClippingBox(mViewportRectangle, 0);
612 secondaryCommandBuffer.SetScissorTestEnable(true);
613 const ClippingBox& layerScissorBox = renderList.GetClippingBox();
614 secondaryCommandBuffer.SetScissor(Rect2DFromClippingBox(layerScissorBox, orientation, graphicsViewport));
615 mScissorStack.push_back(layerScissorBox);
616 mHasLayerScissor = true;
619 // Loop through all RenderItems in the RenderList, set up any prerequisites to render them, then perform the render.
620 for(uint32_t index = 0u; index < count; ++index)
622 const RenderItem& item = renderList.GetItem(index);
624 // Discard renderers outside the root clipping rect
626 if(!rootClippingRect.IsEmpty())
628 auto rect = item.CalculateViewportSpaceAABB(item.mUpdateSize, mViewportRectangle.width, mViewportRectangle.height);
630 if(rect.Intersect(rootClippingRect))
640 DALI_PRINT_RENDER_ITEM(item);
642 // Set up clipping based on both the Renderer and Actor APIs.
643 // The Renderer API will be used if specified. If AUTO, the Actors automatic clipping feature will be used.
644 SetupClipping(item, secondaryCommandBuffer, usedStencilBuffer, lastClippingDepth, lastClippingId, stencilBufferAvailable, instruction, orientation);
646 if(DALI_LIKELY(item.mRenderer))
648 // Set up the depth buffer based on per-renderer flags if depth buffer is available
649 // If the per renderer flags are set to "ON" or "OFF", they will always override any Layer depth mode or
650 // draw-mode state, such as Overlays.
651 // If the flags are set to "AUTO", the behavior then depends on the type of renderer. Overlay Renderers will
652 // always disable depth testing and writing. Color Renderers will enable them if the Layer does.
653 if(depthBufferAvailable == Integration::DepthBufferAvailable::TRUE)
655 SetupDepthBuffer(item, secondaryCommandBuffer, autoDepthTestMode, firstDepthBufferUse);
658 // Depending on whether the renderer has draw commands attached or not the rendering process will
659 // iterate through all the render queues. If there are no draw commands attached, only one
660 // iteration must be done and the default behaviour of the renderer will be executed.
661 // The queues allow to iterate over the same renderer multiple times changing the state of the renderer.
662 // It is similar to the multi-pass rendering.
665 auto const MAX_QUEUE = item.mRenderer->GetDrawCommands().empty() ? 1 : DevelRenderer::RENDER_QUEUE_MAX;
666 for(auto queue = 0u; queue < MAX_QUEUE; ++queue)
668 // Render the item. It will write into the command buffer everything it has to render
669 item.mRenderer->Render(secondaryCommandBuffer, bufferIndex, *item.mNode, item.mModelMatrix, item.mModelViewMatrix, viewMatrix, projectionMatrix, item.mSize, !item.mIsOpaque, boundTextures, instruction, queue);
676 RenderAlgorithms::RenderAlgorithms(Graphics::Controller& graphicsController)
677 : mGraphicsController(graphicsController),
678 mViewportRectangle(),
679 mHasLayerScissor(false)
683 void RenderAlgorithms::ResetCommandBuffer()
685 // Reset main command buffer
686 if(!mGraphicsCommandBuffer)
688 mGraphicsCommandBuffer = mGraphicsController.CreateCommandBuffer(
689 Graphics::CommandBufferCreateInfo()
690 .SetLevel(Graphics::CommandBufferLevel::PRIMARY),
695 mGraphicsCommandBuffer->Reset();
699 void RenderAlgorithms::SubmitCommandBuffer()
701 // Submit main command buffer
702 Graphics::SubmitInfo submitInfo;
703 submitInfo.cmdBuffer.push_back(mGraphicsCommandBuffer.get());
704 submitInfo.flags = 0 | Graphics::SubmitFlagBits::FLUSH;
705 mGraphicsController.SubmitCommandBuffers(submitInfo);
708 void RenderAlgorithms::ProcessRenderInstruction(const RenderInstruction& instruction,
709 BufferIndex bufferIndex,
710 Integration::DepthBufferAvailable depthBufferAvailable,
711 Integration::StencilBufferAvailable stencilBufferAvailable,
712 Vector<Graphics::Texture*>& boundTextures,
713 const Rect<int32_t>& viewport,
714 const Rect<int>& rootClippingRect,
717 DALI_PRINT_RENDER_INSTRUCTION(instruction, bufferIndex);
719 const Matrix* viewMatrix = instruction.GetViewMatrix(bufferIndex);
720 const Matrix* projectionMatrix = instruction.GetProjectionMatrix(bufferIndex);
722 DALI_ASSERT_DEBUG(viewMatrix);
723 DALI_ASSERT_DEBUG(projectionMatrix);
725 if(viewMatrix && projectionMatrix)
727 std::vector<const Graphics::CommandBuffer*> buffers;
728 const RenderListContainer::SizeType count = instruction.RenderListCount();
730 // Iterate through each render list in order. If a pair of render lists
731 // are marked as interleaved, then process them together.
732 for(RenderListContainer::SizeType index = 0; index < count; ++index)
734 const RenderList* renderList = instruction.GetRenderList(index);
736 if(renderList && !renderList->IsEmpty())
738 ProcessRenderList(*renderList,
742 depthBufferAvailable,
743 stencilBufferAvailable,
745 instruction, //added for reflection effect
750 // Execute command buffer
751 auto* commandBuffer = renderList->GetCommandBuffer();
754 buffers.push_back(commandBuffer);
760 mGraphicsCommandBuffer->ExecuteCommandBuffers(std::move(buffers));
765 } // namespace Render
767 } // namespace Internal