/// <summary> /// Constructs a <see cref="Configuration"/>. /// </summary> /// <param name="descriptor">A <see cref="ConfigurationDescriptor"/> for this configuration.</param> /// <param name="features">A set of <see cref="Feature"/>(s) that should be enabled for this configuraton. /// Exaclty zero or one camera mode must be enabled (see <see cref="Feature.UserFacingCamera"/> and <see cref="Feature.WorldFacingCamera"/>). /// If zero camera modes are enabled, no camera texture will be available. Some platforms may support a configuration that does /// not provide camera textures, which can be more performant if they are not necessary. /// All <paramref name="features"/> must be supported by the <paramref name="descriptor"/>.</param> /// <exception cref="System.InvalidOperationException">Thrown if multiple camera modes are enabled.</exception> /// <exception cref="System.InvalidOperationException">Thrown if multiple tracking modes are enabled.</exception> /// <exception cref="System.NotSupportedException">Thrown if the <paramref name="descriptor"/> does not support one or more <paramref name="features"/>.</exception> public Configuration(ConfigurationDescriptor descriptor, Feature features) { if (!descriptor.capabilities.All(features)) { throw new NotSupportedException($"The configuration does not support the following requested features: {features.SetDifference(descriptor.capabilities).ToStringList()}."); } var cameraMode = features.Cameras(); if (cameraMode.Any(Feature.AnyCamera)) { if (cameraMode.Count() > 1) { throw new InvalidOperationException($"Either zero or one camera mode must be enabled. The following modes are enabled: {cameraMode.ToStringList()}"); } } var trackingMode = features.TrackingModes(); if (trackingMode.Count() > 1) { throw new InvalidOperationException($"Either zero or one tracking modes must be enabled. The following modes are enabled: {trackingMode.ToStringList()}"); } this.descriptor = descriptor; this.features = features; }
/// <summary> /// Selects a configuration from the given <paramref name="descriptors"/> and <paramref name="requestedFeatures"/>. /// </summary> /// <remarks> /// Selection works as follows: /// For each of the configuration <paramref name="descriptors"/>, compute the number of supported /// <see cref="Feature"/>s that are present in <paramref name="requestedFeatures"/> and choose the /// configuration descriptor with the highest count. <see cref="ConfigurationDescriptor.rank"/> is /// used to break ties. /// </remarks> /// <param name="descriptors">A set of <see cref="ConfigurationDescriptor"/>s supported by the <see cref="XRSessionSubsystem"/>.</param> /// <param name="requestedFeatures">A set of requested <see cref="Feature"/>s.</param> /// <returns>The configuration that best matches the <paramref name="requestedFeatures"/>.</returns> /// <exception cref="System.ArgumentException">Thrown if <paramref name="descriptors"/> does not contain any descriptors.</exception> /// <exception cref="System.ArgumentException">Thrown if <paramref name="requestedFeatures"/> contains more than one tracking mode.</exception> /// <exception cref="System.ArgumentException">Thrown if <paramref name="requestedFeatures"/> contains more than one camera mode.</exception> public override Configuration ChooseConfiguration(NativeSlice <ConfigurationDescriptor> descriptors, Feature requestedFeatures) { if (descriptors.Length == 0) { throw new ArgumentException("No configuration descriptors to choose from.", nameof(descriptors)); } if (requestedFeatures.Intersection(Feature.AnyTrackingMode).Count() > 1) { throw new ArgumentException($"Zero or one tracking mode must be requested. Requested tracking modes => {requestedFeatures.Intersection(Feature.AnyTrackingMode).ToStringList()}", nameof(requestedFeatures)); } if (requestedFeatures.Intersection(Feature.AnyCamera).Count() > 1) { throw new ArgumentException($"Zero or one camera mode must be requested. Requested camera modes => {requestedFeatures.Intersection(Feature.AnyCamera).ToStringList()}", nameof(requestedFeatures)); } int highestFeatureCount = -1; int highestRank = int.MinValue; ConfigurationDescriptor bestDescriptor = default; foreach (var descriptor in descriptors) { int featureCount = requestedFeatures.Intersection(descriptor.capabilities).Count(); if ((featureCount > highestFeatureCount) || (featureCount == highestFeatureCount && descriptor.rank > highestRank)) { highestFeatureCount = featureCount; highestRank = descriptor.rank; bestDescriptor = descriptor; } } return(new Configuration(bestDescriptor, requestedFeatures.Intersection(bestDescriptor.capabilities))); }