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.
387 inline void RenderAlgorithms::SetupScissorClipping(
388 const RenderItem& item,
389 Graphics::CommandBuffer& commandBuffer,
390 const RenderInstruction& instruction)
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;
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))
406 while(scissorDepth < childStackDepth)
408 mScissorStack.pop_back();
412 // We traversed up the tree, we need to apply a new scissor rectangle (unless we are at the root).
413 traversedUpTree = true;
415 if(clippingNode && childStackDepth > 0u && childStackDepth == scissorDepth) // case of sibling clip area
417 mScissorStack.pop_back();
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)
424 // First, check if we are a clipping node.
427 // This is a clipping node. We generate the AABB for this node and intersect it with the previous intersection further up the tree.
429 // Get the AABB bounding box for the current render item.
430 const ClippingBox scissorBox(item.CalculateViewportSpaceAABB(item.mSize, mViewportRectangle.width, mViewportRectangle.height));
432 // Get the AABB for the parent item that we must intersect with.
433 const ClippingBox& parentBox(mScissorStack.back());
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));
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;
444 // Enable the scissor test based on the above calculation
447 commandBuffer.SetScissorTestEnable(scissorEnabled);
450 // If scissor is enabled, we use the calculated screen-space coordinates (now in the stack).
453 ClippingBox useScissorBox(mScissorStack.back());
455 if(instruction.mFrameBuffer && instruction.GetCamera()->IsYAxisInverted())
457 useScissorBox.y = (instruction.mFrameBuffer->GetHeight() - useScissorBox.height) - useScissorBox.y;
459 Graphics::Rect2D scissorBox = {useScissorBox.x, useScissorBox.y, uint32_t(useScissorBox.width), uint32_t(useScissorBox.height)};
460 commandBuffer.SetScissor(scissorBox);
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)
473 RenderMode::Type renderMode = RenderMode::AUTO;
474 const Renderer* renderer = item.mRenderer;
477 renderMode = renderer->GetRenderMode();
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.
484 case RenderMode::AUTO:
486 // Turn the color buffer on as we always want to render this renderer, regardless of clipping hierarchy.
487 commandBuffer.SetColorMask(true);
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);
495 if(stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
497 SetupStencilClipping(item, commandBuffer, lastClippingDepth, lastClippingId);
502 case RenderMode::NONE:
503 case RenderMode::COLOR:
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)
510 commandBuffer.SetStencilTestEnable(false);
513 // Setup the color buffer based on the RenderMode.
514 commandBuffer.SetColorMask(renderMode == RenderMode::COLOR);
518 case RenderMode::STENCIL:
519 case RenderMode::COLOR_STENCIL:
521 if(stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
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);
528 // Setup the color buffer based on the RenderMode.
529 commandBuffer.SetColorMask(renderMode == RenderMode::COLOR_STENCIL);
531 // If this is the first use of the stencil buffer within this RenderList, clear it (this avoids unnecessary clears).
532 if(!usedStencilBuffer)
534 commandBuffer.ClearStencilBuffer();
535 usedStencilBuffer = true;
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());
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,
564 DALI_PRINT_RENDER_LIST(renderList);
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);
577 mViewportRectangle = viewport;
579 auto* mutableRenderList = const_cast<RenderList*>(&renderList);
580 auto& secondaryCommandBuffer = mutableRenderList->GetCommandBuffer(mGraphicsController);
581 secondaryCommandBuffer.Reset();
583 secondaryCommandBuffer.SetViewport(ViewportFromClippingBox(mViewportRectangle, orientation));
584 mHasLayerScissor = false;
586 // Setup Scissor testing (for both viewport and per-node scissor)
587 mScissorStack.clear();
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())
593 Graphics::Viewport graphicsViewport = ViewportFromClippingBox(mViewportRectangle, 0);
594 secondaryCommandBuffer.SetScissorTestEnable(true);
595 secondaryCommandBuffer.SetScissor(Rect2DFromRect(rootClippingRect, orientation, graphicsViewport));
596 mScissorStack.push_back(rootClippingRect);
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())
601 secondaryCommandBuffer.SetScissorTestEnable(false);
602 mScissorStack.push_back(mViewportRectangle);
605 if(renderList.IsClipping())
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;
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)
618 const RenderItem& item = renderList.GetItem(index);
620 // Discard renderers outside the root clipping rect
622 if(!rootClippingRect.IsEmpty())
624 auto rect = item.CalculateViewportSpaceAABB(item.mUpdateSize, mViewportRectangle.width, mViewportRectangle.height);
626 if(rect.Intersect(rootClippingRect))
636 DALI_PRINT_RENDER_ITEM(item);
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);
642 if(DALI_LIKELY(item.mRenderer))
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)
651 SetupDepthBuffer(item, secondaryCommandBuffer, autoDepthTestMode, firstDepthBufferUse);
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.
661 auto const MAX_QUEUE = item.mRenderer->GetDrawCommands().empty() ? 1 : DevelRenderer::RENDER_QUEUE_MAX;
662 for(auto queue = 0u; queue < MAX_QUEUE; ++queue)
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);
672 RenderAlgorithms::RenderAlgorithms(Graphics::Controller& graphicsController)
673 : mGraphicsController(graphicsController),
674 mViewportRectangle(),
675 mHasLayerScissor(false)
679 void RenderAlgorithms::ResetCommandBuffer()
681 // Reset main command buffer
682 if(!mGraphicsCommandBuffer)
684 mGraphicsCommandBuffer = mGraphicsController.CreateCommandBuffer(
685 Graphics::CommandBufferCreateInfo()
686 .SetLevel(Graphics::CommandBufferLevel::PRIMARY),
691 mGraphicsCommandBuffer->Reset();
695 void RenderAlgorithms::SubmitCommandBuffer()
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);
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,
713 DALI_PRINT_RENDER_INSTRUCTION(instruction, bufferIndex);
715 const Matrix* viewMatrix = instruction.GetViewMatrix(bufferIndex);
716 const Matrix* projectionMatrix = instruction.GetProjectionMatrix(bufferIndex);
718 DALI_ASSERT_DEBUG(viewMatrix);
719 DALI_ASSERT_DEBUG(projectionMatrix);
721 if(viewMatrix && projectionMatrix)
723 std::vector<const Graphics::CommandBuffer*> buffers;
724 const RenderListContainer::SizeType count = instruction.RenderListCount();
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)
730 const RenderList* renderList = instruction.GetRenderList(index);
732 if(renderList && !renderList->IsEmpty())
734 ProcessRenderList(*renderList,
738 depthBufferAvailable,
739 stencilBufferAvailable,
741 instruction, //added for reflection effect
746 // Execute command buffer
747 auto* commandBuffer = renderList->GetCommandBuffer();
750 buffers.push_back(commandBuffer);
756 mGraphicsCommandBuffer->ExecuteCommandBuffers(std::move(buffers));
761 } // namespace Render
763 } // namespace Internal