void Constructor(IPanel panelObj, UIRenderDevice deviceObj, UIRAtlasManager atlasMan, VectorImageManager vectorImageMan) { if (disposed) { DisposeHelper.NotifyDisposedUsed(this); } // A reasonable starting depth level suggested here m_DirtyTracker.heads = new List <VisualElement>(8); m_DirtyTracker.tails = new List <VisualElement>(8); m_DirtyTracker.minDepths = new int[(int)RenderDataDirtyTypeClasses.Count]; m_DirtyTracker.maxDepths = new int[(int)RenderDataDirtyTypeClasses.Count]; m_DirtyTracker.Reset(); if (m_RenderNodesData.Count < 1) { m_RenderNodesData.Add(new RenderNodeData() { matPropBlock = new MaterialPropertyBlock() }); } this.panel = panelObj; this.device = deviceObj; this.atlasManager = atlasMan; this.vectorImageManager = vectorImageMan; this.shaderInfoAllocator.Construct(); painter = new Implementation.UIRStylePainter(this); Font.textureRebuilt += OnFontReset; }
private void RefreshStats(UIRenderDevice renderDevice) { var statistics = renderDevice.GatherAllocationStatistics(); m_GlobalStats.UpdateStats(statistics); m_PagesStats.UpdateStats(statistics); }
static void OnGraphicsResourcesRecreate(bool recreate) { if (!recreate) { UIRenderDevice.PrepareForGfxDeviceRecreate(); } var it = UIElementsUtility.GetPanelsIterator(); while (it.MoveNext()) { if (recreate) { it.Current.Value.atlas?.Reset(); } else { (it.Current.Value.GetUpdater(VisualTreeUpdatePhase.Repaint) as UIRRepaintUpdater)?.DestroyRenderChain(); } } if (!recreate) { UIRenderDevice.FlushAllPendingDeviceDisposes(); } else { UIRenderDevice.WrapUpGfxDeviceRecreate(); } }
internal void AfterRenderDeviceRelease() { if (disposed) { DisposeHelper.NotifyDisposedUsed(this); } Debug.Assert(device == null); device = new UIRenderDevice(Implementation.RenderEvents.ResolveShader((panel as BaseVisualElementPanel)?.standardShader)); Debug.Assert(painter == null); painter = new Implementation.UIRStylePainter(this); ConstructShaderInfoAllocator(); var ve = GetFirstElementInPanel(m_FirstCommand?.owner); while (ve != null) { Implementation.RenderEvents.OnRestoreTransformIDs(ve, device); ve.renderChainData.shaderInfoAlloc = m_FullOpacityShaderInfo; // Reset shader info allocs UIEOnVisualsChanged(ve, false); // Marking dirty will repaint and have the data regenerated ve = ve.renderChainData.next; } UIEOnOpacityChanged(panel.visualTree); }
void OnBeforeDrawChain(UIRenderDevice renderChain) #endif { Material mat = renderChain.GetStandardMaterial(); // Set global graph view shader properties (used by UIR) mat.SetFloat(s_EditorPixelsPerPointId, EditorGUIUtility.pixelsPerPoint); mat.SetFloat(s_GraphViewScaleId, scale); redrawn?.Invoke(); }
static unsafe void PrepareNudgeVertices(VisualElement ve, UIRenderDevice device, MeshHandle mesh, out IntPtr src, out IntPtr dst, out int count) { int vertCount = (int)mesh.allocVerts.size; NativeSlice <Vertex> oldVerts = mesh.allocPage.vertices.cpuData.Slice((int)mesh.allocVerts.start, vertCount); NativeSlice <Vertex> newVerts; device.Update(mesh, (uint)vertCount, out newVerts); src = (IntPtr)oldVerts.GetUnsafePtr(); dst = (IntPtr)newVerts.GetUnsafePtr(); count = vertCount; }
protected RenderChain(IPanel panel, UIRenderDevice device, UIRAtlasManager atlasManager, VectorImageManager vectorImageManager) { if (disposed) { DisposeHelper.NotifyDisposedUsed(this); } this.panel = panel; this.device = device; this.atlasManager = atlasManager; this.vectorImageManager = vectorImageManager; painter = new Implementation.UIRStylePainter(this); Font.textureRebuilt += OnFontReset; }
public RenderChain(IPanel panel, Shader standardShader) { if (disposed) { DisposeHelper.NotifyDisposedUsed(this); } this.panel = panel; device = new UIRenderDevice(Implementation.RenderEvents.ResolveShader(standardShader)); atlasManager = new UIRAtlasManager(); vectorImageManager = new VectorImageManager(atlasManager); painter = new Implementation.UIRStylePainter(this); Font.textureRebuilt += OnFontReset; }
protected RenderChain(IPanel panel, UIRenderDevice device, UIRAtlasManager atlasManager) { if (disposed) { DisposeHelper.NotifyDisposedUsed(this); } this.panel = panel; this.device = device; this.atlasManager = atlasManager; if (atlasManager != null) { atlasManager.ResetPerformed += OnAtlasReset; } painter = new Implementation.UIRStylePainter(this); Font.textureRebuilt += OnFontReset; }
void Constructor(BaseVisualElementPanel panelObj, UIRenderDevice deviceObj, AtlasBase atlas, VectorImageManager vectorImageMan) { if (disposed) { DisposeHelper.NotifyDisposedUsed(this); } // A reasonable starting depth level suggested here m_DirtyTracker.heads = new List <VisualElement>(8); m_DirtyTracker.tails = new List <VisualElement>(8); m_DirtyTracker.minDepths = new int[(int)RenderDataDirtyTypeClasses.Count]; m_DirtyTracker.maxDepths = new int[(int)RenderDataDirtyTypeClasses.Count]; m_DirtyTracker.Reset(); if (m_RenderNodesData.Count < 1) { m_RenderNodesData.Add(new RenderNodeData() { matPropBlock = new MaterialPropertyBlock() }); } this.panel = panelObj; this.device = deviceObj; this.atlas = atlas; this.vectorImageManager = vectorImageMan; // TODO: Share these across all panels vertsPool = new TempAllocator <Vertex>(8192, 2048, 64 * 1024); indicesPool = new TempAllocator <UInt16>(8192 << 1, 2048 << 1, (64 * 1024) << 1); jobManager = new JobManager(); this.shaderInfoAllocator.Construct(); this.opacityIdAccelerator = new OpacityIdAccelerator(); painter = new Implementation.UIRStylePainter(this); var rp = panel as BaseRuntimePanel; if (rp != null && rp.drawToCameras) { drawInCameras = true; m_StaticIndex = RenderChainStaticIndexAllocator.AllocateIndex(this); } }
void Constructor(IPanel panelObj, UIRenderDevice deviceObj, UIRAtlasManager atlasMan, VectorImageManager vectorImageMan) { if (disposed) { DisposeHelper.NotifyDisposedUsed(this); } // A reasonable starting depth level suggested here m_DirtyTracker.heads = new List <VisualElement>(8); m_DirtyTracker.tails = new List <VisualElement>(8); m_DirtyTracker.Reset(); this.panel = panelObj; this.device = deviceObj; this.atlasManager = atlasMan; this.vectorImageManager = vectorImageMan; painter = new Implementation.UIRStylePainter(this); Font.textureRebuilt += OnFontReset; }
internal void AfterRenderDeviceRelease() { if (disposed) { DisposeHelper.NotifyDisposedUsed(this); } Debug.Assert(device == null); var root = m_RenderDeviceRestoreInfo.root; var panelObj = root.panel; var deviceObj = new UIRenderDevice(m_RenderDeviceRestoreInfo.standardShader); var atlasManObj = m_RenderDeviceRestoreInfo.hasAtlasMan ? new UIRAtlasManager() : null; var vectorImageManObj = m_RenderDeviceRestoreInfo.hasVectorImageMan ? new VectorImageManager(atlasManObj) : null; m_RenderDeviceRestoreInfo = new RenderDeviceRestoreInfo(); Constructor(panelObj, deviceObj, atlasManObj, vectorImageManObj); UIEOnChildAdded(root.parent, root, root.hierarchy.parent == null ? 0 : root.hierarchy.parent.IndexOf(panel.visualTree)); }
public void Begin(VisualElement ve, UIRenderDevice device) { Debug.Assert(ve.renderChainData.usesLegacyText && ve.renderChainData.textEntries.Count > 0); this.m_CurrentElement = ve; this.m_TextEntryIndex = 0; Alloc allocVerts = ve.renderChainData.data.allocVerts; NativeSlice <Vertex> slice = ve.renderChainData.data.allocPage.vertices.cpuData.Slice((int)allocVerts.start, (int)allocVerts.size); device.Update(ve.renderChainData.data, ve.renderChainData.data.allocVerts.size, out this.m_MeshDataVerts); RenderChainTextEntry renderChainTextEntry = ve.renderChainData.textEntries[0]; bool flag = ve.renderChainData.textEntries.Count > 1 || renderChainTextEntry.vertexCount != this.m_MeshDataVerts.Length; if (flag) { this.m_MeshDataVerts.CopyFrom(slice); } int firstVertex = renderChainTextEntry.firstVertex; this.m_XFormClipPages = slice[firstVertex].xformClipPages; this.m_IDsFlags = slice[firstVertex].idsFlags; this.m_OpacityPagesSettingsIndex = slice[firstVertex].opacityPageSVGSettingIndex; }
private static void OnGraphicsResourcesRecreate(bool recreate) { bool flag = !recreate; if (flag) { UIRenderDevice.PrepareForGfxDeviceRecreate(); } Dictionary <int, Panel> .Enumerator panelsIterator = UIElementsUtility.GetPanelsIterator(); while (panelsIterator.MoveNext()) { KeyValuePair <int, Panel> current = panelsIterator.Current; UIRRepaintUpdater expr_32 = current.Value.GetUpdater(VisualTreeUpdatePhase.Repaint) as UIRRepaintUpdater; RenderChain renderChain = (expr_32 != null) ? expr_32.renderChain : null; if (recreate) { if (renderChain != null) { renderChain.AfterRenderDeviceRelease(); } } else if (renderChain != null) { renderChain.BeforeRenderDeviceRelease(); } } bool flag2 = !recreate; if (flag2) { UIRenderDevice.FlushAllPendingDeviceDisposes(); } else { UIRenderDevice.WrapUpGfxDeviceRecreate(); } }
protected RenderChain(BaseVisualElementPanel panel, UIRenderDevice device, AtlasBase atlas, VectorImageManager vectorImageManager) { Constructor(panel, device, atlas, vectorImageManager); }
protected RenderChain(IPanel panel, UIRenderDevice device, UIRAtlasManager atlasManager, VectorImageManager vectorImageManager) { Constructor(panel, device, atlasManager, vectorImageManager); }
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); } } }
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); } } }
static void UpdateOrAllocate(ref MeshHandle data, int vertexCount, int indexCount, UIRenderDevice device, out NativeSlice <Vertex> verts, out NativeSlice <UInt16> indices, out UInt16 indexOffset, ref ChainBuilderStats stats) { if (data != null) { // Try to fit within the existing allocation, optionally we can change the condition // to be an exact match of size to guarantee continuity in draw ranges if (data.allocVerts.size >= vertexCount && data.allocIndices.size >= indexCount) { device.Update(data, (uint)vertexCount, (uint)indexCount, out verts, out indices, out indexOffset); stats.updatedMeshAllocations++; } else { // Won't fit in the existing allocated region, free the current one device.Free(data); data = device.Allocate((uint)vertexCount, (uint)indexCount, out verts, out indices, out indexOffset); stats.newMeshAllocations++; } } else { data = device.Allocate((uint)vertexCount, (uint)indexCount, out verts, out indices, out indexOffset); stats.newMeshAllocations++; } }
public static bool NudgeVerticesToNewSpace(VisualElement ve, RenderChain renderChain, UIRenderDevice device) { k_NudgeVerticesMarker.Begin(); Debug.Assert(!ve.renderChainData.disableNudging); Matrix4x4 newTransform; GetVerticesTransformInfo(ve, out newTransform); Matrix4x4 nudgeTransform = newTransform * ve.renderChainData.verticesSpace.inverse; // Attempt to reconstruct the absolute transform. If the result diverges from the absolute // considerably, then we assume that the vertices have become degenerate beyond restoration. // In this case we refuse to nudge, and ask for this element to be fully repainted to regenerate // the vertices without error. const float kMaxAllowedDeviation = 0.0001f; Matrix4x4 reconstructedNewTransform = nudgeTransform * ve.renderChainData.verticesSpace; float error; error = Mathf.Abs(newTransform.m00 - reconstructedNewTransform.m00); error += Mathf.Abs(newTransform.m01 - reconstructedNewTransform.m01); error += Mathf.Abs(newTransform.m02 - reconstructedNewTransform.m02); error += Mathf.Abs(newTransform.m03 - reconstructedNewTransform.m03); error += Mathf.Abs(newTransform.m10 - reconstructedNewTransform.m10); error += Mathf.Abs(newTransform.m11 - reconstructedNewTransform.m11); error += Mathf.Abs(newTransform.m12 - reconstructedNewTransform.m12); error += Mathf.Abs(newTransform.m13 - reconstructedNewTransform.m13); error += Mathf.Abs(newTransform.m20 - reconstructedNewTransform.m20); error += Mathf.Abs(newTransform.m21 - reconstructedNewTransform.m21); error += Mathf.Abs(newTransform.m22 - reconstructedNewTransform.m22); error += Mathf.Abs(newTransform.m23 - reconstructedNewTransform.m23); if (error > kMaxAllowedDeviation) { k_NudgeVerticesMarker.End(); return(false); } ve.renderChainData.verticesSpace = newTransform; // This is the new space of the vertices var job = new NudgeJobData { vertsBeforeUVDisplacement = ve.renderChainData.displacementUVStart, vertsAfterUVDisplacement = ve.renderChainData.displacementUVEnd, transform = nudgeTransform }; PrepareNudgeVertices(ve, device, ve.renderChainData.data, out job.src, out job.dst, out job.count); if (ve.renderChainData.closingData != null) { PrepareNudgeVertices(ve, device, ve.renderChainData.closingData, out job.closingSrc, out job.closingDst, out job.closingCount); } renderChain.jobManager.Add(ref job); k_NudgeVerticesMarker.End(); return(true); }