Example #1
0
 /// <summary>
 /// Clears the collection, including the layout.
 /// </summary>
 public void Clear()
 {
     DataValues   = EmptyData;
     ObjectValues = null;
     layout       = null;
     parameterKeyInfos.Clear();
 }
Example #2
0
        public unsafe ParameterCollection(ParameterCollection parameterCollection)
        {
            // Copy layout
            if (parameterCollection.layout != null)
            {
                layout = parameterCollection.layout;
            }

            // Copy parameter keys
            parameterKeyInfos.AddRange(parameterCollection.parameterKeyInfos);

            // Copy objects
            if (parameterCollection.ObjectValues != null)
            {
                ObjectValues = new object[parameterCollection.ObjectValues.Length];
                for (int i = 0; i < ObjectValues.Length; ++i)
                {
                    ObjectValues[i] = parameterCollection.ObjectValues[i];
                }
            }

            // Copy data
            if (parameterCollection.DataValues != null)
            {
                DataValues = new byte[parameterCollection.DataValues.Length];
                fixed(byte *dataValuesSources = parameterCollection.DataValues)
                fixed(byte *dataValuesDest = DataValues)
                {
                    Utilities.CopyMemory((IntPtr)dataValuesDest, (IntPtr)dataValuesSources, DataValues.Length);
                }
            }
        }
Example #3
0
            private unsafe void PerformFastCopy(ParameterCollectionLayout destinationLayout)
            {
                fixed(byte *destPtr = destination.DataValues)
                fixed(byte *sourcePtr = source.DataValues)
                Utilities.CopyMemory((IntPtr)destPtr, (IntPtr)sourcePtr, destinationLayout.BufferSize);

                var resourceCount = destinationLayout.ResourceCount;
                for (int i = 0; i < resourceCount; ++i)
                {
                    destination.ObjectValues[i] = source.ObjectValues[i];
                }
            }
Example #4
0
 /// <summary>
 /// Adds a <see cref="LogicalGroup"/> layout to a <see cref="ParameterCollectionLayout"/>, so that it is later easy to use with <see cref="UpdateLogicalGroup"/>.
 /// </summary>
 /// <param name="parameterCollectionLayout"></param>
 /// <param name="resourceGroupLayout"></param>
 /// <param name="logicalGroup"></param>
 public static void ProcessLogicalGroup(this ParameterCollectionLayout parameterCollectionLayout, RenderSystemResourceGroupLayout resourceGroupLayout, ref LogicalGroup logicalGroup)
 {
     for (int index = 0; index < logicalGroup.ConstantBufferMemberCount; ++index)
     {
         var member = resourceGroupLayout.ConstantBufferReflection.Members[logicalGroup.ConstantBufferMemberStart + index];
         parameterCollectionLayout.LayoutParameterKeyInfos.Add(new ParameterKeyInfo(member.KeyInfo.Key, parameterCollectionLayout.BufferSize + member.Offset - logicalGroup.ConstantBufferOffset, member.Type.Elements > 0 ? member.Type.Elements : 1));
     }
     for (int index = 0; index < logicalGroup.DescriptorEntryCount; ++index)
     {
         var layoutEntry = resourceGroupLayout.DescriptorSetLayoutBuilder.Entries[logicalGroup.DescriptorEntryStart + index];
         parameterCollectionLayout.LayoutParameterKeyInfos.Add(new ParameterKeyInfo(layoutEntry.Key, parameterCollectionLayout.ResourceCount++));
     }
     parameterCollectionLayout.BufferSize += logicalGroup.ConstantBufferSize;
 }
Example #5
0
            /// <summary>
            /// Compute copy operations. Assumes destination layout is sequential.
            /// </summary>
            /// <param name="dest"></param>
            /// <param name="source"></param>
            /// <param name="keyRoot"></param>
            public void Compile(ParameterCollection dest, ParameterCollection source, string keyRoot)
            {
                ranges      = new List <CopyRange>();
                destination = dest;
                var sourceLayout = new ParameterCollectionLayout();

                // Helper structures to try to keep range contiguous and have as few copy operations as possible (note: there can be some padding)
                var currentDataRange = new CopyRange {
                    IsData = true, DestStart = -1
                };
                var currentResourceRange = new CopyRange {
                    IsResource = true, DestStart = -1
                };

                // Iterate over each variable in dest, and if they match keyRoot, create the equivalent layout in source
                foreach (var parameterKeyInfo in dest.Layout.LayoutParameterKeyInfos)
                {
                    bool isResource = parameterKeyInfo.BindingSlot != -1;
                    bool isData     = parameterKeyInfo.Offset != -1;

                    if (parameterKeyInfo.Key.Name.EndsWith(keyRoot))
                    {
                        // That's a match
                        var subkeyName = parameterKeyInfo.Key.Name.Substring(0, parameterKeyInfo.Key.Name.Length - keyRoot.Length);
                        var subkey     = ParameterKeys.FindByName(subkeyName);

                        if (isData)
                        {
                            // First time since range reset, let's setup destination offset
                            if (currentDataRange.DestStart == -1)
                            {
                                currentDataRange.DestStart = parameterKeyInfo.Offset;
                            }

                            // Might be some empty space (padding)
                            currentDataRange.Size = parameterKeyInfo.Offset - currentDataRange.DestStart;

                            sourceLayout.LayoutParameterKeyInfos.Add(new ParameterKeyInfo(subkey, currentDataRange.SourceStart + currentDataRange.Size, parameterKeyInfo.Count));

                            var elementCount = parameterKeyInfo.Count;
                            var elementSize  = parameterKeyInfo.Key.Size;
                            var size         = (elementSize + 15) / 16 * 16 * (elementCount - 1) + elementSize;

                            currentDataRange.Size += size;
                        }
                        else if (isResource)
                        {
                            // First time since range reset, let's setup destination offset
                            if (currentResourceRange.DestStart == -1)
                            {
                                currentResourceRange.DestStart = parameterKeyInfo.BindingSlot;
                            }

                            // Might be some empty space (padding) (probably unlikely for resources...)
                            currentResourceRange.Size = parameterKeyInfo.BindingSlot - currentResourceRange.DestStart;

                            sourceLayout.LayoutParameterKeyInfos.Add(new ParameterKeyInfo(subkey, currentResourceRange.SourceStart + currentResourceRange.Size));

                            currentResourceRange.Size += parameterKeyInfo.Count;
                        }
                    }
                    else
                    {
                        // Found one item not part of the range, let's finish it
                        if (isData)
                        {
                            FlushRangeIfNecessary(ref currentDataRange);
                        }
                        else if (isResource)
                        {
                            FlushRangeIfNecessary(ref currentResourceRange);
                        }
                    }
                }

                // Finish ranges
                FlushRangeIfNecessary(ref currentDataRange);
                FlushRangeIfNecessary(ref currentResourceRange);

                // Update sizes
                sourceLayout.BufferSize    = currentDataRange.SourceStart;
                sourceLayout.ResourceCount = currentResourceRange.SourceStart;

                source.UpdateLayout(sourceLayout);
            }
Example #6
0
        /// <summary>
        /// Reorganizes internal data and resources to match the given objects, and append extra values at the end.
        /// </summary>
        /// <param name="collectionLayout"></param>
        public unsafe void UpdateLayout(ParameterCollectionLayout collectionLayout)
        {
            var oldLayout = this.layout;

            this.layout = collectionLayout;

            // Same layout, or removed layout
            if (oldLayout == collectionLayout || collectionLayout == null)
            {
                return;
            }

            var layoutParameterKeyInfos = collectionLayout.LayoutParameterKeyInfos;

            // Do a first pass to measure constant buffer size
            var newParameterKeyInfos = new FastList <ParameterKeyInfo>(Math.Max(1, parameterKeyInfos.Count));

            newParameterKeyInfos.AddRange(parameterKeyInfos);
            var processedParameters = new bool[parameterKeyInfos.Count];

            var bufferSize    = collectionLayout.BufferSize;
            var resourceCount = collectionLayout.ResourceCount;

            foreach (var layoutParameterKeyInfo in layoutParameterKeyInfos)
            {
                // Find the same parameter in old collection
                // Is this parameter already added?
                for (int i = 0; i < parameterKeyInfos.Count; ++i)
                {
                    if (parameterKeyInfos[i].Key == layoutParameterKeyInfo.Key)
                    {
                        processedParameters[i]        = true;
                        newParameterKeyInfos.Items[i] = layoutParameterKeyInfo;
                        break;
                    }
                }
            }

            // Append new elements that don't exist in new layouts (to preserve their values)
            for (int i = 0; i < processedParameters.Length; ++i)
            {
                // Skip parameters already processed before
                if (processedParameters[i])
                {
                    continue;
                }

                var parameterKeyInfo = newParameterKeyInfos[i];

                if (parameterKeyInfo.Offset != -1)
                {
                    // It's data
                    newParameterKeyInfos.Items[i].Offset = bufferSize;

                    var elementSize  = newParameterKeyInfos.Items[i].Key.Size;
                    var elementCount = newParameterKeyInfos.Items[i].Count;
                    var totalSize    = elementSize + (elementSize + 15) / 16 * 16 * (elementCount - 1);
                    bufferSize += totalSize;
                }
                else if (parameterKeyInfo.BindingSlot != -1)
                {
                    // It's a resource
                    newParameterKeyInfos.Items[i].BindingSlot = resourceCount++;
                }
            }

            var newDataValues     = new byte[bufferSize];
            var newResourceValues = new object[resourceCount];

            // Update default values
            var bufferOffset = 0;

            foreach (var layoutParameterKeyInfo in layoutParameterKeyInfos)
            {
                if (layoutParameterKeyInfo.Offset != -1)
                {
                    // It's data
                    // TODO: Set default value
                    var defaultValueMetadata = layoutParameterKeyInfo.Key?.DefaultValueMetadata;
                    if (defaultValueMetadata != null)
                    {
                        fixed(byte *newDataValuesPtr = newDataValues)
                        defaultValueMetadata.WriteBuffer((IntPtr)newDataValuesPtr + bufferOffset + layoutParameterKeyInfo.Offset, 16);
                    }
                }
            }

            // Second pass to copy existing data at new offsets/slots
            for (int i = 0; i < parameterKeyInfos.Count; ++i)
            {
                var parameterKeyInfo    = parameterKeyInfos[i];
                var newParameterKeyInfo = newParameterKeyInfos[i];

                if (newParameterKeyInfo.Offset != -1)
                {
                    var elementSize  = newParameterKeyInfos.Items[i].Key.Size;
                    var newTotalSize = elementSize + (elementSize + 15) / 16 * 16 * (newParameterKeyInfo.Count - 1);
                    var totalSize    = elementSize + (elementSize + 15) / 16 * 16 * (parameterKeyInfo.Count - 1);

                    // It's data
                    fixed(byte *dataValues = DataValues)
                    fixed(byte *newDataValuesPtr = newDataValues)
                    Utilities.CopyMemory((IntPtr)newDataValuesPtr + newParameterKeyInfo.Offset, (IntPtr)dataValues + parameterKeyInfo.Offset, Math.Min(newTotalSize, totalSize));
                }
                else if (newParameterKeyInfo.BindingSlot != -1)
                {
                    // It's a resource
                    newResourceValues[newParameterKeyInfo.BindingSlot] = ObjectValues[parameterKeyInfo.BindingSlot];
                }
            }

            // Update new content
            parameterKeyInfos = newParameterKeyInfos;

            DataValues   = newDataValues;
            ObjectValues = newResourceValues;
        }