/// <summary> /// Clears the collection, including the layout. /// </summary> public void Clear() { DataValues = EmptyData; ObjectValues = null; layout = null; parameterKeyInfos.Clear(); }
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); } } }
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]; } }
/// <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; }
/// <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); }
/// <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; }