internal void Update(ParameterUpdaterDefinition definition) { var sortedKeyHashes = definition.SortedKeyHashes; var sortedKeyHashesLength = sortedKeyHashes.Length; if (sortedKeyHashesLength == 0) { return; } if (sortedKeyHashesLength > InternalValues.Length) { InternalValues = new BoundInternalValue[sortedKeyHashesLength]; } // Optimization: nothing changed? if (previousParameterCollections == null || previousParameterCollections.Length < parameterCollections.Length) { previousParameterCollections = new int[parameterCollections.Length]; } bool needUpdate = false; for (int levelIndex = 0; levelIndex < parameterCollections.Length; ++levelIndex) { var parameterCollection = parameterCollections[levelIndex]; var keyCounter = parameterCollection.KeyVersion; if (keyCounter != previousParameterCollections[levelIndex]) { needUpdate = true; previousParameterCollections[levelIndex] = keyCounter; } } if (!needUpdate) { return; } // Temporary clear data for debug/test purposes (shouldn't necessary) for (int i = 0; i < sortedKeyHashesLength; ++i) { InternalValues[i] = new BoundInternalValue(); } // Optimization: List is already prepared (with previous SetKeyMapping() call) var collection = parameterCollections[0]; var keys = collection.IndexedInternalValues; for (int i = 0; i < keys.Length; ++i) { var internalValue = keys[i]; if (internalValue != null) { InternalValues[i] = new BoundInternalValue(0, internalValue); } } // Iterate over parameter collections for (int levelIndex = 1; levelIndex < parameterCollections.Length; ++levelIndex) { var level = parameterCollections[levelIndex].InternalValues; int index = 0; var currentHash = sortedKeyHashes[index]; int internalValueCount = level.Count; var items = level.Items; // Iterate over each items // Since both expected values and parameter collection values are sorted, // we iterate over both of them together so that we can easily detect what needs to be copied. // Note: We use a 64-bit hash that we assume has no collision (maybe we should // detect unlikely collision when registering them?) for (int i = 0; i < internalValueCount; ++i) { var internalValue = items[i]; var expectedHash = internalValue.Key.HashCode; //index = InternalValueBinarySearch(sortedKeyHashes, internalValue.Key.GetHashCode()); while (currentHash < expectedHash) { if (++index >= sortedKeyHashesLength) { break; } currentHash = sortedKeyHashes[index]; } if (currentHash == expectedHash) { // Update element InternalValues[index] = new BoundInternalValue(levelIndex, internalValue.Value); } } } }
internal void Update(GraphicsDevice graphicsDevice, EffectParameterUpdaterDefinition definition) { Update(definition); // ---------------------------------------------------------------- // Update dynamic values // Definitions based on Default+Pass lists // ---------------------------------------------------------------- var dependencies = definition.Dependencies; for (int dependencyIndex = 0; dependencyIndex < dependencies.Length; ++dependencyIndex) { var dependency = dependencies[dependencyIndex]; int highestLevel = 0; int destinationLevel = InternalValues[dependency.Destination].DirtyCount; var destination = InternalValues[dependency.Destination]; bool needUpdate = false; for (int i = 0; i < dependency.Sources.Length; ++i) { var source = InternalValues[dependency.Sources[i]]; var sourceLevel = source.DirtyCount; if (highestLevel < sourceLevel) { highestLevel = sourceLevel; } } if (destinationLevel < highestLevel) { // Dynamic value: the sources of this dynamic value are defined in a most derived collection than its destination collection // as a result, we need to create or use a new dynamic value at the appropriate level. // Find last collection index (excluding parameterOverrides) int maxLevelNoOverride = parameterCollections.Length - 1; if (highestLevel <= maxLevelNoOverride) { // TODO: Choose target level more properly (i.e. mesh*pass => meshpass) // Sources all comes from normal collections => override in the most derived collection // For now, use maxLevelNoOverride instead of highestLevel just to be safe. var bestCollectionForDynamicValue = parameterCollections[maxLevelNoOverride]; var key = definition.SortedKeys[dependency.Destination]; bestCollectionForDynamicValue.SetDefault(key, true); InternalValues[dependency.Destination] = destination = new BoundInternalValue(highestLevel, bestCollectionForDynamicValue.GetInternalValue(key)); } else { // At least one source comes from TLS override, so use dynamic from TLS dynamic storage as well. InternalValues[dependency.Destination] = destination = new BoundInternalValue(parameterCollections.Length, definition.ThreadLocalDynamicValues[graphicsDevice.ThreadIndex][dependencyIndex]); } needUpdate = true; } // Force updating (even if no parameters has been updated) if (!dependency.Dynamic.AutoCheckDependencies) { needUpdate = true; } if (destination.Value.Dependencies == null || destination.Value.Dependencies.Length < dependency.Sources.Length) { destination.Value.Dependencies = new ParameterCollection.InternalValueReference[dependency.Sources.Length]; } var dependencyParameters = destination.Value.Dependencies; for (int i = 0; i < dependency.Sources.Length; ++i) { var source = InternalValues[dependency.Sources[i]]; var internalValue = source.Value; if (dependencyParameters[i].Entry != internalValue) { needUpdate = true; dependencyParameters[i].Entry = internalValue; dependencyParameters[i].Counter = internalValue.Counter; } else if (dependencyParameters[i].Counter != internalValue.Counter) { needUpdate = true; dependencyParameters[i].Counter = internalValue.Counter; } } if (needUpdate) { // At least one source was updated dependency.Dynamic.GetValue(destination.Value); destination.Value.Counter++; } } }
internal void Update(ParameterUpdaterDefinition definition) { var sortedKeyHashes = definition.SortedKeyHashes; var sortedKeyHashesLength = sortedKeyHashes.Length; if (sortedKeyHashesLength == 0) return; if (sortedKeyHashesLength > InternalValues.Length) InternalValues = new BoundInternalValue[sortedKeyHashesLength]; // Optimization: nothing changed? if (previousParameterCollections == null || previousParameterCollections.Length < parameterCollections.Length) { previousParameterCollections = new int[parameterCollections.Length]; } bool needUpdate = false; for (int levelIndex = 0; levelIndex < parameterCollections.Length; ++levelIndex) { var parameterCollection = parameterCollections[levelIndex]; var keyCounter = parameterCollection.KeyVersion; if (keyCounter != previousParameterCollections[levelIndex]) { needUpdate = true; previousParameterCollections[levelIndex] = keyCounter; } } if (!needUpdate) { return; } // Temporary clear data for debug/test purposes (shouldn't necessary) for (int i = 0; i < sortedKeyHashesLength; ++i) InternalValues[i] = new BoundInternalValue(); // Optimization: List is already prepared (with previous SetKeyMapping() call) var collection = parameterCollections[0]; var keys = collection.IndexedInternalValues; for (int i = 0; i < keys.Length; ++i) { var internalValue = keys[i]; if (internalValue != null) InternalValues[i] = new BoundInternalValue(0, internalValue); } // Iterate over parameter collections for (int levelIndex = 1; levelIndex < parameterCollections.Length; ++levelIndex) { var level = parameterCollections[levelIndex].InternalValues; int index = 0; var currentHash = sortedKeyHashes[index]; int internalValueCount = level.Count; var items = level.Items; // Iterate over each items // Since both expected values and parameter collection values are sorted, // we iterate over both of them together so that we can easily detect what needs to be copied. // Note: We use a 64-bit hash that we assume has no collision (maybe we should // detect unlikely collision when registering them?) for (int i = 0; i < internalValueCount; ++i) { var internalValue = items[i]; var expectedHash = internalValue.Key.HashCode; //index = InternalValueBinarySearch(sortedKeyHashes, internalValue.Key.GetHashCode()); while (currentHash < expectedHash) { if (++index >= sortedKeyHashesLength) break; currentHash = sortedKeyHashes[index]; } if (currentHash == expectedHash) { // Update element InternalValues[index] = new BoundInternalValue(levelIndex, internalValue.Value); } } } }