internal static void ProcessOnTransformOrSizeChanged(RenderChain renderChain, VisualElement ve, uint dirtyID, ref ChainBuilderStats stats)
 {
     stats.recursiveTransformUpdates++;
     DepthFirstOnTransformOrSizeChanged(renderChain, ve.hierarchy.parent, ve, dirtyID, renderChain.device, false, false, ref stats);
 }
        static void DepthFirstOnOpacityChanged(RenderChain renderChain, float parentCompositeOpacity, VisualElement ve,
                                               uint dirtyID, bool hierarchical, ref ChainBuilderStats stats, bool isDoingFullVertexRegeneration = false)
        {
            if (dirtyID == ve.renderChainData.dirtyID)
            {
                return;
            }

            ve.renderChainData.dirtyID = dirtyID; // Prevent reprocessing of the same element in the same pass
            stats.recursiveOpacityUpdatesExpanded++;
            float oldOpacity = ve.renderChainData.compositeOpacity;
            float newOpacity = ve.resolvedStyle.opacity * parentCompositeOpacity;

            const float meaningfullOpacityChange = 0.0001f;

            bool visiblityTresholdPassed = (oldOpacity < VisibilityTreshold ^ newOpacity < VisibilityTreshold);
            bool compositeOpacityChanged = Mathf.Abs(oldOpacity - newOpacity) > meaningfullOpacityChange || visiblityTresholdPassed;

            if (compositeOpacityChanged)
            {
                // Avoid updating cached opacity if it changed too little, because we don't want slow changes to
                // update the cache and never trigger the compositeOpacityChanged condition.
                // The only small change allowed is when we cross the "visible" boundary of VisibilityTreshold
                ve.renderChainData.compositeOpacity = newOpacity;
            }

            bool changedOpacityID   = false;
            bool hasDistinctOpacity = newOpacity < parentCompositeOpacity - meaningfullOpacityChange; //assume 0 <= opacity <= 1

            if (hasDistinctOpacity)
            {
                if (ve.renderChainData.opacityID.ownedState == OwnedState.Inherited)
                {
                    changedOpacityID             = true;
                    ve.renderChainData.opacityID = renderChain.shaderInfoAllocator.AllocOpacity();
                }

                if ((changedOpacityID || compositeOpacityChanged) && ve.renderChainData.opacityID.IsValid())
                {
                    renderChain.shaderInfoAllocator.SetOpacityValue(ve.renderChainData.opacityID, newOpacity);
                }
            }
            else if (ve.renderChainData.opacityID.ownedState == OwnedState.Inherited)
            {
                // Just follow my parent's alloc
                if (ve.hierarchy.parent != null &&
                    !ve.renderChainData.opacityID.Equals(ve.hierarchy.parent.renderChainData.opacityID))
                {
                    changedOpacityID                        = true;
                    ve.renderChainData.opacityID            = ve.hierarchy.parent.renderChainData.opacityID;
                    ve.renderChainData.opacityID.ownedState = OwnedState.Inherited;
                }
            }
            else
            {
                // I have an owned allocation, but I must match my parent's opacity, just set the opacity rather than free and inherit our parent's
                if (compositeOpacityChanged && ve.renderChainData.opacityID.IsValid())
                {
                    renderChain.shaderInfoAllocator.SetOpacityValue(ve.renderChainData.opacityID, newOpacity);
                }
            }

            if (isDoingFullVertexRegeneration)
            {
                // A parent already called UIEOnVisualsChanged with hierarchical=true
            }
            else if (changedOpacityID && ((ve.renderChainData.dirtiedValues & RenderDataDirtyTypes.Visuals) == 0) &&
                     (ve.renderChainData.data != null || ve.renderChainData.closingData != null))
            {
                renderChain.UIEOnOpacityIdChanged(ve); // Changed opacity ID, must update vertices.. we don't do it hierarchical here since our children will go through this too
            }

            if (compositeOpacityChanged || changedOpacityID || hierarchical)
            {
                // Recurse on children
                int childrenCount = ve.hierarchy.childCount;
                for (int i = 0; i < childrenCount; i++)
                {
                    DepthFirstOnOpacityChanged(renderChain, newOpacity, ve.hierarchy[i], dirtyID, hierarchical, ref stats,
                                               isDoingFullVertexRegeneration);
                }
            }
        }
        static void DepthFirstOnClippingChanged(RenderChain renderChain,
                                                VisualElement parent,
                                                VisualElement ve,
                                                uint dirtyID,
                                                bool hierarchical,
                                                bool isRootOfChange,               // MUST be true  on the root call.
                                                bool isPendingHierarchicalRepaint, // MUST be false on the root call.
                                                bool inheritedClipRectIDChanged,   // MUST be false on the root call.
                                                bool inheritedMaskingChanged,      // MUST be false on the root call.
                                                UIRenderDevice device,
                                                ref ChainBuilderStats stats)
        {
            bool upToDate = dirtyID == ve.renderChainData.dirtyID;

            if (upToDate && !inheritedClipRectIDChanged && !inheritedMaskingChanged)
            {
                return;
            }

            ve.renderChainData.dirtyID = dirtyID; // Prevent reprocessing of the same element in the same pass

            if (!isRootOfChange)
            {
                stats.recursiveClipUpdatesExpanded++;
            }

            isPendingHierarchicalRepaint |= (ve.renderChainData.dirtiedValues & RenderDataDirtyTypes.VisualsHierarchy) != 0;

            // Internal operations (done in this call) to do:
            bool mustUpdateClipRectID      = hierarchical || isRootOfChange || inheritedClipRectIDChanged;
            bool mustUpdateClippingMethod  = hierarchical || isRootOfChange;
            bool mustUpdateChildrenMasking = hierarchical || isRootOfChange || inheritedMaskingChanged;

            // External operations (done by recursion or postponed) to do:
            bool mustRepaintThis       = false;
            bool mustRepaintHierarchy  = false;
            bool mustProcessSizeChange = false;
            // mustRecurse implies recursing on all children, but doesn't force anything beyond them.
            // hierarchical implies recursing on all descendants
            // As a result, hierarchical implies mustRecurse
            bool mustRecurse = hierarchical;

            ClipMethod oldClippingMethod = ve.renderChainData.clipMethod;
            ClipMethod newClippingMethod = mustUpdateClippingMethod ? DetermineSelfClipMethod(renderChain, ve) : oldClippingMethod;

            // Shader discard support
            bool clipRectIDChanged = false;

            if (mustUpdateClipRectID)
            {
                BMPAlloc newClipRectID = ve.renderChainData.clipRectID;
                if (newClippingMethod == ClipMethod.ShaderDiscard)
                {
                    if (!RenderChainVEData.AllocatesID(ve.renderChainData.clipRectID))
                    {
                        newClipRectID = renderChain.shaderInfoAllocator.AllocClipRect();
                        if (!newClipRectID.IsValid())
                        {
                            newClippingMethod = ClipMethod.Scissor; // Fallback to scissor since we couldn't allocate a clipRectID
                            // Both shader discard and scisorring work with world-clip rectangles, so no need
                            // to inherit any clipRectIDs for such elements, our own scissor rect clips up correctly
                            newClipRectID = UIRVEShaderInfoAllocator.infiniteClipRect;
                        }
                    }
                }
                else
                {
                    if (RenderChainVEData.AllocatesID(ve.renderChainData.clipRectID))
                    {
                        renderChain.shaderInfoAllocator.FreeClipRect(ve.renderChainData.clipRectID);
                    }

                    // Inherit parent's clipRectID if possible.
                    // Group transforms shouldn't inherit the clipRectID since they have a new frame of reference,
                    // they provide a new baseline with the _PixelClipRect instead.
                    if ((ve.renderHints & RenderHints.GroupTransform) == 0)
                    {
                        newClipRectID            = ((newClippingMethod != ClipMethod.Scissor) && (parent != null)) ? parent.renderChainData.clipRectID : UIRVEShaderInfoAllocator.infiniteClipRect;
                        newClipRectID.ownedState = OwnedState.Inherited;
                    }
                }

                clipRectIDChanged = !ve.renderChainData.clipRectID.Equals(newClipRectID);
                Debug.Assert((ve.renderHints & RenderHints.GroupTransform) == 0 || !clipRectIDChanged);
                ve.renderChainData.clipRectID = newClipRectID;
            }

            bool maskingChanged = false;

            if (oldClippingMethod != newClippingMethod)
            {
                ve.renderChainData.clipMethod = newClippingMethod;

                if (oldClippingMethod == ClipMethod.Stencil || newClippingMethod == ClipMethod.Stencil)
                {
                    maskingChanged            = true;
                    mustUpdateChildrenMasking = true;
                }

                if (oldClippingMethod == ClipMethod.Scissor || newClippingMethod == ClipMethod.Scissor)
                {
                    // We need to add/remove scissor push/pop commands
                    mustRepaintThis = true;
                }

                if (newClippingMethod == ClipMethod.ShaderDiscard || oldClippingMethod == ClipMethod.ShaderDiscard && RenderChainVEData.AllocatesID(ve.renderChainData.clipRectID))
                {
                    // We must update the clipping rects.
                    mustProcessSizeChange = true;
                }
            }

            if (clipRectIDChanged)
            {
                // Our children MUST update their render data clipRectIDs
                mustRecurse = true;

                // Our children MUST update their vertex clipRectIDs
                mustRepaintHierarchy = true;
            }

            if (mustUpdateChildrenMasking)
            {
                int newChildrenMaskDepth  = 0;
                int newChildrenStencilRef = 0;
                if (parent != null)
                {
                    newChildrenMaskDepth  = parent.renderChainData.childrenMaskDepth;
                    newChildrenStencilRef = parent.renderChainData.childrenStencilRef;
                    if (newClippingMethod == ClipMethod.Stencil)
                    {
                        if (newChildrenMaskDepth > newChildrenStencilRef)
                        {
                            ++newChildrenStencilRef;
                        }
                        ++newChildrenMaskDepth;
                    }

                    // When applying the MaskContainer hint, we skip because the last depth level because even though we
                    // could technically increase the reference value, it would be useless since there won't be more
                    // deeply nested masks that could benefit from it.
                    if ((ve.renderHints & RenderHints.MaskContainer) == RenderHints.MaskContainer && newChildrenMaskDepth < UIRUtility.k_MaxMaskDepth)
                    {
                        newChildrenStencilRef = newChildrenMaskDepth;
                    }
                }

                if (ve.renderChainData.childrenMaskDepth != newChildrenMaskDepth || ve.renderChainData.childrenStencilRef != newChildrenStencilRef)
                {
                    maskingChanged = true;
                }

                ve.renderChainData.childrenMaskDepth  = newChildrenMaskDepth;
                ve.renderChainData.childrenStencilRef = newChildrenStencilRef;
            }

            if (maskingChanged)
            {
                mustRecurse = true; // Our children must update their inherited state.

                // These optimizations would allow to skip repainting the hierarchy:
                // a) We could update the stencilRef in the commands without repainting
                // b) The winding order could be reversed without repainting (when required)
                // In the meantime, we have no other choice but to request a hierarchical repaint.
                mustRepaintHierarchy = true;
            }

            if ((mustRepaintThis || mustRepaintHierarchy) && !isPendingHierarchicalRepaint)
            {
                renderChain.UIEOnVisualsChanged(ve, mustRepaintHierarchy);
                isPendingHierarchicalRepaint = true;
            }

            if (mustProcessSizeChange)
            {
                renderChain.UIEOnTransformOrSizeChanged(ve, false, true);
            }

            if (mustRecurse)
            {
                int childrenCount = ve.hierarchy.childCount;
                for (int i = 0; i < childrenCount; i++)
                {
                    DepthFirstOnClippingChanged(
                        renderChain,
                        ve,
                        ve.hierarchy[i],
                        dirtyID,
                        // Having to recurse doesn't mean that we need to process ALL descendants. For example, the
                        // propagation of the transformId may stop if a group or a bone is encountered.
                        hierarchical,
                        false,
                        isPendingHierarchicalRepaint,
                        clipRectIDChanged,
                        maskingChanged,
                        device,
                        ref stats);
                }
            }
        }
 internal static void ProcessOnColorChanged(RenderChain renderChain, VisualElement ve, uint dirtyID, ref ChainBuilderStats stats)
 {
     stats.colorUpdates++;
     OnColorChanged(renderChain, ve, dirtyID, ref stats);
 }
        public unsafe static UIRStylePainter.ClosingInfo PaintElement(RenderChain renderChain, VisualElement ve, ref ChainBuilderStats stats)
        {
            var device = renderChain.device;

            var isClippingWithStencil  = ve.renderChainData.clipMethod == ClipMethod.Stencil;
            var isClippingWithScissors = ve.renderChainData.clipMethod == ClipMethod.Scissor;

            if ((UIRUtility.IsElementSelfHidden(ve) && !isClippingWithStencil && !isClippingWithScissors) || ve.renderChainData.isHierarchyHidden)
            {
                if (ve.renderChainData.data != null)
                {
                    device.Free(ve.renderChainData.data);
                    ve.renderChainData.data = null;
                }
                if (ve.renderChainData.firstCommand != null)
                {
                    ResetCommands(renderChain, ve);
                }

                renderChain.ResetTextures(ve);

                return(new UIRStylePainter.ClosingInfo());
            }

            // Retain our command insertion points if possible, to avoid paying the cost of finding them again
            RenderChainCommand oldCmdPrev = ve.renderChainData.firstCommand?.prev;
            RenderChainCommand oldCmdNext = ve.renderChainData.lastCommand?.next;
            RenderChainCommand oldClosingCmdPrev, oldClosingCmdNext;
            bool commandsAndClosingCommandsWereConsecutive = (ve.renderChainData.firstClosingCommand != null) && (oldCmdNext == ve.renderChainData.firstClosingCommand);

            if (commandsAndClosingCommandsWereConsecutive)
            {
                oldCmdNext        = ve.renderChainData.lastClosingCommand.next;
                oldClosingCmdPrev = oldClosingCmdNext = null;
            }
            else
            {
                oldClosingCmdPrev = ve.renderChainData.firstClosingCommand?.prev;
                oldClosingCmdNext = ve.renderChainData.lastClosingCommand?.next;
            }
            Debug.Assert(oldCmdPrev?.owner != ve);
            Debug.Assert(oldCmdNext?.owner != ve);
            Debug.Assert(oldClosingCmdPrev?.owner != ve);
            Debug.Assert(oldClosingCmdNext?.owner != ve);

            ResetCommands(renderChain, ve);
            renderChain.ResetTextures(ve);

            k_GenerateEntries.Begin();
            var painter = renderChain.painter;

            painter.Begin(ve);

            if (ve.visible)
            {
                painter.DrawVisualElementBackground();
                painter.DrawVisualElementBorder();
                painter.ApplyVisualElementClipping();

                InvokeGenerateVisualContent(ve, painter.meshGenerationContext);
            }
            else
            {
                // Even though the element hidden, we still have to push the stencil shape or setup the scissors in case any children are visible.
                if (isClippingWithScissors || isClippingWithStencil)
                {
                    painter.ApplyVisualElementClipping();
                }
            }
            k_GenerateEntries.End();

            MeshHandle data = ve.renderChainData.data;

            if (painter.totalVertices > device.maxVerticesPerPage)
            {
                Debug.LogError($"A {nameof(VisualElement)} must not allocate more than {device.maxVerticesPerPage } vertices.");

                if (data != null)
                {
                    device.Free(data);
                    data = null;
                }

                renderChain.ResetTextures(ve);

                // Restart without drawing anything.
                painter.Reset();
                painter.Begin(ve);
            }

            // Convert entries to commands.
            var entries = painter.entries;

            if (entries.Count > 0)
            {
                NativeSlice <Vertex> verts   = new NativeSlice <Vertex>();
                NativeSlice <UInt16> indices = new NativeSlice <UInt16>();
                UInt16 indexOffset           = 0;

                if (painter.totalVertices > 0)
                {
                    UpdateOrAllocate(ref data, painter.totalVertices, painter.totalIndices, device, out verts, out indices, out indexOffset, ref stats);
                }

                int vertsFilled = 0, indicesFilled = 0;

                RenderChainCommand cmdPrev = oldCmdPrev, cmdNext = oldCmdNext;
                if (oldCmdPrev == null && oldCmdNext == null)
                {
                    FindCommandInsertionPoint(ve, out cmdPrev, out cmdNext);
                }

                // Vertex data, lazily computed
                bool      vertexDataComputed = false;
                Matrix4x4 transform          = Matrix4x4.identity;
                Color32   xformClipPages     = new Color32(0, 0, 0, 0);
                Color32   ids                  = new Color32(0, 0, 0, 0);
                Color32   addFlags             = new Color32(0, 0, 0, 0);
                Color32   opacityPage          = new Color32(0, 0, 0, 0);
                Color32   textCoreSettingsPage = new Color32(0, 0, 0, 0);

                k_ConvertEntriesToCommandsMarker.Begin();
                int firstDisplacementUV = -1, lastDisplacementUVPlus1 = -1;
                foreach (var entry in painter.entries)
                {
                    if (entry.vertices.Length > 0 && entry.indices.Length > 0)
                    {
                        if (!vertexDataComputed)
                        {
                            vertexDataComputed = true;
                            GetVerticesTransformInfo(ve, out transform);
                            ve.renderChainData.verticesSpace = transform; // This is the space for the generated vertices below
                        }

                        Color32 transformData        = renderChain.shaderInfoAllocator.TransformAllocToVertexData(ve.renderChainData.transformID);
                        Color32 opacityData          = renderChain.shaderInfoAllocator.OpacityAllocToVertexData(ve.renderChainData.opacityID);
                        Color32 textCoreSettingsData = renderChain.shaderInfoAllocator.TextCoreSettingsToVertexData(ve.renderChainData.textCoreSettingsID);
                        xformClipPages.r = transformData.r;
                        xformClipPages.g = transformData.g;
                        ids.r            = transformData.b;
                        opacityPage.r    = opacityData.r;
                        opacityPage.g    = opacityData.g;
                        ids.b            = opacityData.b;
                        if (entry.isTextEntry)
                        {
                            // It's important to avoid writing these values when the vertices aren't for text,
                            // as these settings are shared with the vector graphics gradients.
                            // The same applies to the CopyTransformVertsPos* methods below.
                            textCoreSettingsPage.r = textCoreSettingsData.r;
                            textCoreSettingsPage.g = textCoreSettingsData.g;
                            ids.a = textCoreSettingsData.b;
                        }

                        Color32 clipRectData = renderChain.shaderInfoAllocator.ClipRectAllocToVertexData(entry.clipRectID);
                        xformClipPages.b = clipRectData.r;
                        xformClipPages.a = clipRectData.g;
                        ids.g            = clipRectData.b;
                        addFlags.r       = (byte)entry.addFlags;

                        float textureId = entry.texture.ConvertToGpu();

                        // Copy vertices, transforming them as necessary
                        var targetVerticesSlice = verts.Slice(vertsFilled, entry.vertices.Length);

                        if (entry.uvIsDisplacement)
                        {
                            if (firstDisplacementUV < 0)
                            {
                                firstDisplacementUV     = vertsFilled;
                                lastDisplacementUVPlus1 = vertsFilled + entry.vertices.Length;
                            }
                            else if (lastDisplacementUVPlus1 == vertsFilled)
                            {
                                lastDisplacementUVPlus1 += entry.vertices.Length;
                            }
                            else
                            {
                                ve.renderChainData.disableNudging = true;  // Disjoint displacement UV entries, we can't keep track of them, so disable nudging optimization altogether
                            }
                        }

                        int  entryIndexCount         = entry.indices.Length;
                        int  entryIndexOffset        = vertsFilled + indexOffset;
                        var  targetIndicesSlice      = indices.Slice(indicesFilled, entryIndexCount);
                        bool shapeWindingIsClockwise = UIRUtility.ShapeWindingIsClockwise(entry.maskDepth, entry.stencilRef);
                        bool transformFlipsWinding   = ve.renderChainData.worldFlipsWinding;

                        var job = new ConvertMeshJobData
                        {
                            vertSrc              = (IntPtr)entry.vertices.GetUnsafePtr(),
                            vertDst              = (IntPtr)targetVerticesSlice.GetUnsafePtr(),
                            vertCount            = targetVerticesSlice.Length,
                            transform            = transform,
                            transformUVs         = entry.uvIsDisplacement ? 1 : 0,
                            xformClipPages       = xformClipPages,
                            ids                  = ids,
                            addFlags             = addFlags,
                            opacityPage          = opacityPage,
                            textCoreSettingsPage = textCoreSettingsPage,
                            isText               = entry.isTextEntry ? 1 : 0,
                            textureId            = textureId,

                            indexSrc    = (IntPtr)entry.indices.GetUnsafePtr(),
                            indexDst    = (IntPtr)targetIndicesSlice.GetUnsafePtr(),
                            indexCount  = targetIndicesSlice.Length,
                            indexOffset = entryIndexOffset,
                            flipIndices = shapeWindingIsClockwise == transformFlipsWinding ? 1 : 0
                        };
                        renderChain.jobManager.Add(ref job);

                        if (entry.isClipRegisterEntry)
                        {
                            painter.LandClipRegisterMesh(targetVerticesSlice, targetIndicesSlice, entryIndexOffset);
                        }

                        var cmd = InjectMeshDrawCommand(renderChain, ve, ref cmdPrev, ref cmdNext, data, entryIndexCount, indicesFilled, entry.material, entry.texture, entry.stencilRef);
                        if (entry.isTextEntry)
                        {
                            // Set font atlas texture gradient scale
                            cmd.state.sdfScale = entry.fontTexSDFScale;
                        }

                        vertsFilled   += entry.vertices.Length;
                        indicesFilled += entryIndexCount;
                    }
                    else if (entry.customCommand != null)
                    {
                        InjectCommandInBetween(renderChain, entry.customCommand, ref cmdPrev, ref cmdNext);
                    }
                    else
                    {
                        Debug.Assert(false); // Unable to determine what kind of command to generate here
                    }
                }

                if (!ve.renderChainData.disableNudging && (firstDisplacementUV >= 0))
                {
                    ve.renderChainData.displacementUVStart = firstDisplacementUV;
                    ve.renderChainData.displacementUVEnd   = lastDisplacementUVPlus1;
                }

                k_ConvertEntriesToCommandsMarker.End();
            }
            else if (data != null)
            {
                device.Free(data);
                data = null;
            }
            ve.renderChainData.data = data;

            if (painter.closingInfo.clipperRegisterIndices.Length == 0 && ve.renderChainData.closingData != null)
            {
                // No more closing data needed, so free it now
                device.Free(ve.renderChainData.closingData);
                ve.renderChainData.closingData = null;
            }

            if (painter.closingInfo.needsClosing)
            {
                k_GenerateClosingCommandsMarker.Begin();
                RenderChainCommand cmdPrev = oldClosingCmdPrev, cmdNext = oldClosingCmdNext;
                if (commandsAndClosingCommandsWereConsecutive)
                {
                    cmdPrev = ve.renderChainData.lastCommand;
                    cmdNext = cmdPrev.next;
                }
                else if (cmdPrev == null && cmdNext == null)
                {
                    FindClosingCommandInsertionPoint(ve, out cmdPrev, out cmdNext);
                }

                if (painter.closingInfo.PopDefaultMaterial)
                {
                    var cmd = renderChain.AllocCommand();
                    cmd.type    = CommandType.PopDefaultMaterial;
                    cmd.closing = true;
                    cmd.owner   = ve;
                    InjectClosingCommandInBetween(renderChain, cmd, ref cmdPrev, ref cmdNext);
                }

                if (painter.closingInfo.blitAndPopRenderTexture)
                {
                    {
                        var cmd = renderChain.AllocCommand();
                        cmd.type           = CommandType.BlitToPreviousRT;
                        cmd.closing        = true;
                        cmd.owner          = ve;
                        cmd.state.material = GetBlitMaterial(ve.subRenderTargetMode);
                        Debug.Assert(cmd.state.material != null);
                        InjectClosingCommandInBetween(renderChain, cmd, ref cmdPrev, ref cmdNext);
                    }

                    {
                        var cmd = renderChain.AllocCommand();
                        cmd.type    = CommandType.PopRenderTexture;
                        cmd.closing = true;
                        cmd.owner   = ve;
                        InjectClosingCommandInBetween(renderChain, cmd, ref cmdPrev, ref cmdNext);
                    }
                }

                if (painter.closingInfo.clipperRegisterIndices.Length > 0)
                {
                    var cmd = InjectClosingMeshDrawCommand(renderChain, ve, ref cmdPrev, ref cmdNext, null, 0, 0, null, TextureId.invalid, painter.closingInfo.maskStencilRef);
                    painter.LandClipUnregisterMeshDrawCommand(cmd); // Placeholder command that will be filled actually later
                }
                if (painter.closingInfo.popViewMatrix)
                {
                    var cmd = renderChain.AllocCommand();
                    cmd.type    = CommandType.PopView;
                    cmd.closing = true;
                    cmd.owner   = ve;
                    InjectClosingCommandInBetween(renderChain, cmd, ref cmdPrev, ref cmdNext);
                }
                if (painter.closingInfo.popScissorClip)
                {
                    var cmd = renderChain.AllocCommand();
                    cmd.type    = CommandType.PopScissor;
                    cmd.closing = true;
                    cmd.owner   = ve;
                    InjectClosingCommandInBetween(renderChain, cmd, ref cmdPrev, ref cmdNext);
                }
                k_GenerateClosingCommandsMarker.End();
            }

            // When we have a closing mesh, we must have an opening mesh. At least we assumed where we decide
            // whether we must nudge or not: we only test whether the opening mesh is non-null.
            Debug.Assert(ve.renderChainData.closingData == null || ve.renderChainData.data != null);

            var closingInfo = painter.closingInfo;

            painter.Reset();
            return(closingInfo);
        }
        internal static uint DepthFirstOnChildRemoving(RenderChain renderChain, VisualElement ve)
        {
            // Recurse on children
            int  childrenCount = ve.hierarchy.childCount - 1;
            uint deepCount     = 0;

            while (childrenCount >= 0)
            {
                deepCount += DepthFirstOnChildRemoving(renderChain, ve.hierarchy[childrenCount--]);
            }

            if (ve.renderChainData.isInChain)
            {
                renderChain.ChildWillBeRemoved(ve);
                CommandGenerator.ResetCommands(renderChain, ve);
                renderChain.ResetTextures(ve);
                ve.renderChainData.isInChain  = false;
                ve.renderChainData.clipMethod = ClipMethod.Undetermined;

                if (ve.renderChainData.next != null)
                {
                    ve.renderChainData.next.renderChainData.prev = ve.renderChainData.prev;
                }
                if (ve.renderChainData.prev != null)
                {
                    ve.renderChainData.prev.renderChainData.next = ve.renderChainData.next;
                }

                if (RenderChainVEData.AllocatesID(ve.renderChainData.textCoreSettingsID))
                {
                    renderChain.shaderInfoAllocator.FreeTextCoreSettings(ve.renderChainData.textCoreSettingsID);
                    ve.renderChainData.textCoreSettingsID = UIRVEShaderInfoAllocator.defaultTextCoreSettings;
                }
                if (RenderChainVEData.AllocatesID(ve.renderChainData.opacityID))
                {
                    renderChain.shaderInfoAllocator.FreeOpacity(ve.renderChainData.opacityID);
                    ve.renderChainData.opacityID = UIRVEShaderInfoAllocator.fullOpacity;
                }
                if (RenderChainVEData.AllocatesID(ve.renderChainData.colorID))
                {
                    renderChain.shaderInfoAllocator.FreeColor(ve.renderChainData.colorID);
                    ve.renderChainData.colorID = BMPAlloc.Invalid;
                }
                if (RenderChainVEData.AllocatesID(ve.renderChainData.backgroundColorID))
                {
                    renderChain.shaderInfoAllocator.FreeColor(ve.renderChainData.backgroundColorID);
                    ve.renderChainData.backgroundColorID = BMPAlloc.Invalid;
                }
                if (RenderChainVEData.AllocatesID(ve.renderChainData.borderLeftColorID))
                {
                    renderChain.shaderInfoAllocator.FreeColor(ve.renderChainData.borderLeftColorID);
                    ve.renderChainData.borderLeftColorID = BMPAlloc.Invalid;
                }
                if (RenderChainVEData.AllocatesID(ve.renderChainData.borderTopColorID))
                {
                    renderChain.shaderInfoAllocator.FreeColor(ve.renderChainData.borderTopColorID);
                    ve.renderChainData.borderTopColorID = BMPAlloc.Invalid;
                }
                if (RenderChainVEData.AllocatesID(ve.renderChainData.borderRightColorID))
                {
                    renderChain.shaderInfoAllocator.FreeColor(ve.renderChainData.borderRightColorID);
                    ve.renderChainData.borderRightColorID = BMPAlloc.Invalid;
                }
                if (RenderChainVEData.AllocatesID(ve.renderChainData.borderBottomColorID))
                {
                    renderChain.shaderInfoAllocator.FreeColor(ve.renderChainData.borderBottomColorID);
                    ve.renderChainData.borderBottomColorID = BMPAlloc.Invalid;
                }
                if (RenderChainVEData.AllocatesID(ve.renderChainData.tintColorID))
                {
                    renderChain.shaderInfoAllocator.FreeColor(ve.renderChainData.tintColorID);
                    ve.renderChainData.tintColorID = BMPAlloc.Invalid;
                }
                if (RenderChainVEData.AllocatesID(ve.renderChainData.clipRectID))
                {
                    renderChain.shaderInfoAllocator.FreeClipRect(ve.renderChainData.clipRectID);
                    ve.renderChainData.clipRectID = UIRVEShaderInfoAllocator.infiniteClipRect;
                }
                if (RenderChainVEData.AllocatesID(ve.renderChainData.transformID))
                {
                    renderChain.shaderInfoAllocator.FreeTransform(ve.renderChainData.transformID);
                    ve.renderChainData.transformID = UIRVEShaderInfoAllocator.identityTransform;
                }
                ve.renderChainData.boneTransformAncestor = ve.renderChainData.groupTransformAncestor = null;
                if (ve.renderChainData.closingData != null)
                {
                    renderChain.device.Free(ve.renderChainData.closingData);
                    ve.renderChainData.closingData = null;
                }
                if (ve.renderChainData.data != null)
                {
                    renderChain.device.Free(ve.renderChainData.data);
                    ve.renderChainData.data = null;
                }
            }
            return(deepCount + 1);
        }
示例#7
0
 public void SetRenderChain(RenderChain renderChain)
 {
     renderObjects.Clear();
     renderChain.GetRenderObjects(renderObjects);
 }
 public Clip Add(RenderChain.RenderChain filter)
 {
     if (filter == null)
     {
         throw new ArgumentNullException("filter");
     }
     Filter += filter;
     return this;
 }
            public FilterClip Add(RenderChain.RenderChain chain)
            {
                if (chain == null)
                {
                    throw new ArgumentNullException("chain");
                }
                Filter += chain;

                return this;
            }
 public FilterClip Apply(RenderChain.RenderChain chain)
 {
     return Add(chain);
 }
示例#11
0
 public static void RenderAndClear(this RenderChain renderChain)
 {
     renderChain.Render();
     renderChain.Clear();
 }
示例#12
0
 public override void AddToRenderChain(RenderChain chain)
 {
 }
        public static void ResetCommands(RenderChain renderChain, VisualElement ve)
        {
            if (ve.renderChainData.firstCommand != null)
            {
                renderChain.OnRenderCommandsRemoved(ve.renderChainData.firstCommand, ve.renderChainData.lastCommand);
            }

            var prev = ve.renderChainData.firstCommand != null ? ve.renderChainData.firstCommand.prev : null;
            var next = ve.renderChainData.lastCommand != null ? ve.renderChainData.lastCommand.next : null;

            Debug.Assert(prev == null || prev.owner != ve);
            Debug.Assert(next == null || next == ve.renderChainData.firstClosingCommand || next.owner != ve);
            if (prev != null)
            {
                prev.next = next;
            }
            if (next != null)
            {
                next.prev = prev;
            }

            if (ve.renderChainData.firstCommand != null)
            {
                var c = ve.renderChainData.firstCommand;
                while (c != ve.renderChainData.lastCommand)
                {
                    var nextC = c.next;
                    renderChain.FreeCommand(c);
                    c = nextC;
                }
                renderChain.FreeCommand(c); // Last command
            }
            ve.renderChainData.firstCommand = ve.renderChainData.lastCommand = null;

            prev = ve.renderChainData.firstClosingCommand != null ? ve.renderChainData.firstClosingCommand.prev : null;
            next = ve.renderChainData.lastClosingCommand != null ? ve.renderChainData.lastClosingCommand.next : null;
            Debug.Assert(prev == null || prev.owner != ve);
            Debug.Assert(next == null || next.owner != ve);
            if (prev != null)
            {
                prev.next = next;
            }
            if (next != null)
            {
                next.prev = prev;
            }

            if (ve.renderChainData.firstClosingCommand != null)
            {
                renderChain.OnRenderCommandsRemoved(ve.renderChainData.firstClosingCommand, ve.renderChainData.lastClosingCommand);

                var c = ve.renderChainData.firstClosingCommand;
                while (c != ve.renderChainData.lastClosingCommand)
                {
                    var nextC = c.next;
                    renderChain.FreeCommand(c);
                    c = nextC;
                }
                renderChain.FreeCommand(c); // Last closing command
            }
            ve.renderChainData.firstClosingCommand = ve.renderChainData.lastClosingCommand = null;
        }
        static void DepthFirstOnTransformOrSizeChanged(RenderChain renderChain, VisualElement parent, VisualElement ve, uint dirtyID, UIRenderDevice device, bool isAncestorOfChangeSkinned, bool transformChanged, ref ChainBuilderStats stats)
        {
            if (dirtyID == ve.renderChainData.dirtyID)
            {
                return;
            }

            stats.recursiveTransformUpdatesExpanded++;

            transformChanged |= (ve.renderChainData.dirtiedValues & RenderDataDirtyTypes.Transform) != 0;

            if (RenderChainVEData.AllocatesID(ve.renderChainData.clipRectID))
            {
                renderChain.shaderInfoAllocator.SetClipRectValue(ve.renderChainData.clipRectID, GetClipRectIDClipInfo(ve));
            }

            if (transformChanged && UpdateLocalFlipsWinding(ve))
            {
                renderChain.UIEOnVisualsChanged(ve, true);
            }

            bool dirtyHasBeenResolved = true;

            if (RenderChainVEData.AllocatesID(ve.renderChainData.transformID))
            {
                renderChain.shaderInfoAllocator.SetTransformValue(ve.renderChainData.transformID, GetTransformIDTransformInfo(ve));
                isAncestorOfChangeSkinned = true;
                stats.boneTransformed++;
            }
            else if (!transformChanged)
            {
                // Only the clip info had to be updated, we can skip the other cases which are for transform changes only.
            }
            else if ((ve.renderHints & RenderHints.GroupTransform) != 0)
            {
                stats.groupTransformElementsChanged++;
            }
            else if (isAncestorOfChangeSkinned)
            {
                // Children of a bone element inherit the transform data change automatically when the root updates that data, no need to do anything for children
                Debug.Assert(RenderChainVEData.InheritsID(ve.renderChainData.transformID)); // The element MUST have a transformID that has been inherited from an ancestor
                dirtyHasBeenResolved = false;                                               // We just skipped processing, if another later transform change is queued on this element this pass then we should still process it
                stats.skipTransformed++;
            }
            else if ((ve.renderChainData.dirtiedValues & (RenderDataDirtyTypes.Visuals | RenderDataDirtyTypes.VisualsHierarchy)) == 0 && (ve.renderChainData.data != null))
            {
                // If a visual update will happen, then skip work here as the visual update will incorporate the transformed vertices
                if (!ve.renderChainData.disableNudging && CommandGenerator.NudgeVerticesToNewSpace(ve, renderChain, device))
                {
                    stats.nudgeTransformed++;
                }
                else
                {
                    renderChain.UIEOnVisualsChanged(ve, false); // Nudging not allowed, so do a full visual repaint
                    stats.visualUpdateTransformed++;
                }
            }

            if (dirtyHasBeenResolved)
            {
                ve.renderChainData.dirtyID = dirtyID; // Prevent reprocessing of the same element in the same pass
            }
            // Make sure to pre-evaluate world transform and clip now so we don't do it at render time
            if (renderChain.drawInCameras)
            {
                ve.EnsureWorldTransformAndClipUpToDate();
            }

            if ((ve.renderHints & RenderHints.GroupTransform) == 0)
            {
                // Recurse on children
                int childrenCount = ve.hierarchy.childCount;
                for (int i = 0; i < childrenCount; i++)
                {
                    DepthFirstOnTransformOrSizeChanged(renderChain, ve, ve.hierarchy[i], dirtyID, device, isAncestorOfChangeSkinned, transformChanged, ref stats);
                }
            }
        }
示例#15
0
        public override void DrawRenderChain(RenderChain renderChain)
        {
            var cmd = AddCommand <DrawRenderChainCommand>();

            cmd.SetRenderChain(renderChain);
        }
 public Clip(RenderChain.RenderChain chain, IFilter input)
 {
     m_Chain = chain;
     Filter = input;
 }
        internal static uint DepthFirstOnChildAdded(RenderChain renderChain, VisualElement parent, VisualElement ve, int index, bool resetState)
        {
            Debug.Assert(ve.panel != null);

            if (ve.renderChainData.isInChain)
            {
                return(0); // Already added, redundant call
            }
            if (resetState)
            {
                ve.renderChainData = new RenderChainVEData();
            }

            ve.renderChainData.isInChain           = true;
            ve.renderChainData.verticesSpace       = Matrix4x4.identity;
            ve.renderChainData.transformID         = UIRVEShaderInfoAllocator.identityTransform;
            ve.renderChainData.clipRectID          = UIRVEShaderInfoAllocator.infiniteClipRect;
            ve.renderChainData.opacityID           = UIRVEShaderInfoAllocator.fullOpacity;
            ve.renderChainData.colorID             = BMPAlloc.Invalid; // Rely on vertex tint color by default
            ve.renderChainData.backgroundColorID   = BMPAlloc.Invalid;
            ve.renderChainData.borderLeftColorID   = BMPAlloc.Invalid;
            ve.renderChainData.borderTopColorID    = BMPAlloc.Invalid;
            ve.renderChainData.borderRightColorID  = BMPAlloc.Invalid;
            ve.renderChainData.borderBottomColorID = BMPAlloc.Invalid;
            ve.renderChainData.tintColorID         = BMPAlloc.Invalid;
            ve.renderChainData.textCoreSettingsID  = UIRVEShaderInfoAllocator.defaultTextCoreSettings;
            ve.renderChainData.compositeOpacity    = float.MaxValue; // Any unreasonable value will do to trip the opacity composer to work
            UpdateLocalFlipsWinding(ve);

            if (parent != null)
            {
                if ((parent.renderHints & (RenderHints.GroupTransform)) != 0)
                {
                    ve.renderChainData.groupTransformAncestor = parent;
                }
                else
                {
                    ve.renderChainData.groupTransformAncestor = parent.renderChainData.groupTransformAncestor;
                }
                ve.renderChainData.hierarchyDepth = parent.renderChainData.hierarchyDepth + 1;
            }
            else
            {
                ve.renderChainData.groupTransformAncestor = null;
                ve.renderChainData.hierarchyDepth         = 0;
            }

            renderChain.EnsureFitsDepth(ve.renderChainData.hierarchyDepth);

            if (index > 0)
            {
                Debug.Assert(parent != null);
                ve.renderChainData.prev = GetLastDeepestChild(parent.hierarchy[index - 1]);
            }
            else
            {
                ve.renderChainData.prev = parent;
            }
            ve.renderChainData.next = ve.renderChainData.prev != null ? ve.renderChainData.prev.renderChainData.next : null;

            if (ve.renderChainData.prev != null)
            {
                ve.renderChainData.prev.renderChainData.next = ve;
            }
            if (ve.renderChainData.next != null)
            {
                ve.renderChainData.next.renderChainData.prev = ve;
            }

            // TransformID
            // Since transform type is controlled by render hints which are locked on the VE by now, we can
            // go ahead and prep transform data now and never check on it again under regular circumstances
            Debug.Assert(!RenderChainVEData.AllocatesID(ve.renderChainData.transformID));
            if (NeedsTransformID(ve))
            {
                ve.renderChainData.transformID = renderChain.shaderInfoAllocator.AllocTransform(); // May fail, that's ok
            }
            else
            {
                ve.renderChainData.transformID = BMPAlloc.Invalid;
            }
            ve.renderChainData.boneTransformAncestor = null;

            if (NeedsColorID(ve))
            {
                InitColorIDs(renderChain, ve);
                SetColorValues(renderChain, ve);
            }

            if (!RenderChainVEData.AllocatesID(ve.renderChainData.transformID))
            {
                if (parent != null && (ve.renderHints & RenderHints.GroupTransform) == 0)
                {
                    if (RenderChainVEData.AllocatesID(parent.renderChainData.transformID))
                    {
                        ve.renderChainData.boneTransformAncestor = parent;
                    }
                    else
                    {
                        ve.renderChainData.boneTransformAncestor = parent.renderChainData.boneTransformAncestor;
                    }

                    ve.renderChainData.transformID            = parent.renderChainData.transformID;
                    ve.renderChainData.transformID.ownedState = OwnedState.Inherited; // Mark this allocation as not owned by us (inherited)
                }
                else
                {
                    ve.renderChainData.transformID = UIRVEShaderInfoAllocator.identityTransform;
                }
            }
            else
            {
                renderChain.shaderInfoAllocator.SetTransformValue(ve.renderChainData.transformID, GetTransformIDTransformInfo(ve));
            }

            // Recurse on children
            int  childrenCount = ve.hierarchy.childCount;
            uint deepCount     = 0;

            for (int i = 0; i < childrenCount; i++)
            {
                deepCount += DepthFirstOnChildAdded(renderChain, ve, ve.hierarchy[i], i, resetState);
            }
            return(1 + deepCount);
        }
 public Clip Apply(RenderChain.RenderChain filter)
 {
     return Add(filter);
 }
        public unsafe static void ClosePaintElement(VisualElement ve, UIRStylePainter.ClosingInfo closingInfo, RenderChain renderChain, ref ChainBuilderStats stats)
        {
            if (closingInfo.clipperRegisterIndices.Length > 0)
            {
                NativeSlice <Vertex> verts   = new NativeSlice <Vertex>();
                NativeSlice <UInt16> indices = new NativeSlice <UInt16>();
                UInt16 indexOffset           = 0;

                // Due to device Update limitations, we cannot share the vertices of the registration mesh. It would be great
                // if we can just point winding-flipped indices towards the same vertices as the registration mesh.
                // For now, we duplicate the registration mesh entirely, wasting a bit of vertex memory
                UpdateOrAllocate(ref ve.renderChainData.closingData, closingInfo.clipperRegisterVertices.Length, closingInfo.clipperRegisterIndices.Length, renderChain.device, out verts, out indices, out indexOffset, ref stats);
                var job = new CopyClosingMeshJobData
                {
                    vertSrc     = (IntPtr)closingInfo.clipperRegisterVertices.GetUnsafePtr(),
                    vertDst     = (IntPtr)verts.GetUnsafePtr(),
                    vertCount   = verts.Length,
                    indexSrc    = (IntPtr)closingInfo.clipperRegisterIndices.GetUnsafePtr(),
                    indexDst    = (IntPtr)indices.GetUnsafePtr(),
                    indexCount  = indices.Length,
                    indexOffset = indexOffset - closingInfo.clipperRegisterIndexOffset
                };
                renderChain.jobManager.Add(ref job);
                closingInfo.clipUnregisterDrawCommand.mesh       = ve.renderChainData.closingData;
                closingInfo.clipUnregisterDrawCommand.indexCount = indices.Length;
            }
        }