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++;
     }
 }
Пример #2
0
 internal Mesh(Engine engine, MeshHandle handle)
 {
     this.engine    = engine;
     Handle         = handle;
     VerticesBuffer = engine.Device.CreateBuffer <UniversalVertex>(BufferTypeEnum.Vertex, 1);
     IndicesBuffer  = engine.Device.CreateBuffer <int>(BufferTypeEnum.Index, 1);
 }
Пример #3
0
 internal Mesh(Engine engine, MeshHandle handle, UniversalVertex[] vertices, int[] indices)
 {
     this.engine    = engine;
     Handle         = handle;
     VerticesBuffer = engine.Device.CreateBuffer <UniversalVertex>(BufferTypeEnum.Vertex, vertices);
     IndicesBuffer  = engine.Device.CreateBuffer <int>(BufferTypeEnum.Index, indices);
     this.vertices  = vertices;
     this.indices   = indices;
 }
        static void DoUpdateOpacityId(VisualElement ve, RenderChain renderChain, MeshHandle mesh)
        {
            int vertCount = (int)mesh.allocVerts.size;
            NativeSlice <Vertex> oldVerts = mesh.allocPage.vertices.cpuData.Slice((int)mesh.allocVerts.start, vertCount);

            renderChain.device.Update(mesh, (uint)vertCount, out NativeSlice <Vertex> newVerts);
            Color32 opacityData = renderChain.shaderInfoAllocator.OpacityAllocToVertexData(ve.renderChainData.opacityID);

            renderChain.opacityIdAccelerator.CreateJob(oldVerts, newVerts, opacityData, vertCount);
        }
Пример #5
0
        MeshHandle GetMeshHandle(ProBuilderMesh mesh, Dictionary <ProBuilderMesh, MeshHandle> cache)
        {
            MeshHandle handle;

            if (!cache.TryGetValue(mesh, out handle))
            {
                var m = m_MeshPool.Get();
                handle = new MeshHandle(mesh.transform, m);
                cache.Add(mesh, handle);
            }

            return(handle);
        }
        void RebuildMeshHandle(ProBuilderMesh mesh, Dictionary <ProBuilderMesh, MeshHandle> list, Action <ProBuilderMesh, Mesh> ctor)
        {
            MeshHandle handle;

            if (!list.TryGetValue(mesh, out handle))
            {
                var m = m_MeshPool.Get();
                handle = new MeshHandle(mesh.transform, m);
                list.Add(mesh, handle);
            }

            ctor(mesh, handle.mesh);
        }
Пример #7
0
        // @todo: not thread safe!
        public IMesh CreateMesh(Vector3[] vertices, int[] indices)
        {
            var handle = new MeshHandle(meshes.Count);

            var mesh = new Mesh(engine, handle);

            mesh.SetVertices(vertices);
            mesh.SetIndices(indices, 0);
            mesh.Rebuild();

            meshes.Add(mesh);

            return(mesh);
        }
Пример #8
0
        public override unsafe void Add(T item)
        {
            var mesh = item.Mesh;

            Add(mesh, item);

            // Each mesh only needs to be buffered to GPU memory once (the first time it's used).
            if (mesh.Handle != null)
            {
                return;
            }

            var data    = GetData(mesh);
            var indices = mesh.Indices;
            var handle  = new MeshHandle(indices.Length, (int)buffer.IndexSize, buffer.BaseVertex);

            buffer.Buffer(data, indices);

            mesh.Handle = handle;
        }
Пример #9
0
        // @todo: not thread safe!
        public IMesh CreateMesh(MeshData meshData)
        {
            var handle = new MeshHandle(meshes.Count);

            UniversalVertex[] vertices = new UniversalVertex[meshData.Vertices.Length];
            for (int i = 0; i < vertices.Length; ++i)
            {
                vertices[i] = new UniversalVertex()
                {
                    position = new Vector4(meshData.Vertices[i], 1),
                    normal   = new Vector4(meshData.Normals[i], 0),
                    uv1      = meshData.UV[i]
                };
            }

            var mesh = new Mesh(engine, handle, vertices, meshData.Indices);

            meshes.Add(mesh);

            return(mesh);
        }
Пример #10
0
        public override unsafe void Add(T item)
        {
            Mesh mesh = item.Mesh;

            Add(mesh, item);

            // Each mesh only needs to be buffered to GPU memory once (the first time it's used).
            if (mesh.Handle != null)
            {
                return;
            }

            float[]  data    = GetData(mesh);
            ushort[] indices = mesh.Indices;

            int size           = sizeof(float) * data.Length;
            int localIndexSize = sizeof(ushort) * indices.Length;

            var handle = new MeshHandle(indices.Length, indexSize, maxIndex);

            mesh.Handle = handle;

            maxIndex += mesh.MaxIndex + 1;
            glBindBuffer(GL_ARRAY_BUFFER, bufferId);

            fixed(float *address = &data[0])
            {
                glBufferSubData(GL_ARRAY_BUFFER, bufferSize, (uint)size, address);
            }

            bufferSize += size;
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexId);

            fixed(ushort *address = &indices[0])
            {
                glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexSize, (uint)localIndexSize, address);
            }

            indexSize += localIndexSize;
        }
        public RenderHandle RegisterRenderer(MeshHandle meshHandle, Material material, Transform transform)
        {
            var mesh   = engine.meshManager.GetMeshByHandle(meshHandle);
            var shader = material.ShaderHandle;

            if (!renderers.ContainsKey(shader))
            {
                renderers[shader] = new Dictionary <Material, Dictionary <Mesh, List <Transform> > >();
            }

            if (!renderers[shader].ContainsKey(material))
            {
                renderers[shader][material] = new Dictionary <Mesh, List <Transform> >();
            }

            if (!renderers[shader][material].ContainsKey(mesh))
            {
                renderers[shader][material][mesh] = new List <Transform>();
            }

            renderers[shader][material][mesh].Add(transform);

            return(new RenderHandle());
        }
Пример #12
0
 internal Mesh GetMeshByHandle(MeshHandle mesh)
 {
     return(meshes[mesh.Handle]);
 }
        static RenderChainCommand InjectClosingMeshDrawCommand(RenderChain renderChain, VisualElement ve, ref RenderChainCommand cmdPrev, ref RenderChainCommand cmdNext, MeshHandle mesh, int indexCount, int indexOffset, Material material, TextureId texture, int stencilRef)
        {
            var cmd = renderChain.AllocCommand();

            cmd.type    = CommandType.Draw;
            cmd.closing = true;
            cmd.state   = new State {
                material = material, texture = texture, stencilRef = stencilRef
            };
            cmd.mesh        = mesh;
            cmd.indexOffset = indexOffset;
            cmd.indexCount  = indexCount;
            cmd.owner       = ve;
            InjectClosingCommandInBetween(renderChain, cmd, ref cmdPrev, ref cmdNext);
            return(cmd);
        }
        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;
        }
        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;
            var isGroup = (ve.renderHints & RenderHints.GroupTransform) != 0; // Groups need to push view and scissors

            if ((UIRUtility.IsElementSelfHidden(ve) && !isClippingWithStencil && !isClippingWithScissors && !isGroup) || 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);
        }