/// <summary>Called when the multisample type changes</summary> private void OnMultisampleTypeChanged(object sender, EventArgs e) { ComboBox cb = sender as ComboBox; MultiSampleType mst = (MultiSampleType)cb.GetSelectedData(); globalSettings.presentParams.MultiSample = mst; EnumDeviceSettingsCombo combo = GetCurrentDeviceSettingsCombo(); int maxQuality = 0; for (int i = 0; i < combo.multiSampleTypeList.Count; i++) { MultiSampleType msType = (MultiSampleType)combo.multiSampleTypeList[i]; if (msType == mst) { maxQuality = (int)combo.multiSampleQualityList[i]; } } // We have the max quality now, add to our list multiSampleQualityCombo.Clear(); for (int i = 0; i < maxQuality; i++) { if (!multiSampleQualityCombo.ContainsItem(i.ToString())) { multiSampleQualityCombo.AddItem(i.ToString(), i); } } multiSampleQualityCombo.SetSelectedByData(globalSettings.presentParams.MultiSampleQuality); OnMultisampleQualityChanged(multiSampleQualityCombo, e); }
/// <summary> /// Adds all depth/stencil formats that are compatible with the device /// and application to the given device combo /// </summary> private static void BuildDepthStencilFormatList(EnumDeviceSettingsCombo deviceCombo) { foreach (DepthFormat depthStencil in depthStencilPossibleList) { if (Manager.CheckDeviceFormat((int)deviceCombo.AdapterOrdinal, deviceCombo.DeviceType, deviceCombo.AdapterFormat, Usage.DepthStencil, ResourceType.Surface, depthStencil)) { // This can be used as a depth stencil, make sure it matches if (Manager.CheckDepthStencilMatch((int)deviceCombo.AdapterOrdinal, deviceCombo.DeviceType, deviceCombo.AdapterFormat, deviceCombo.BackBufferFormat, depthStencil)) { // Yup, add it deviceCombo.depthStencilFormatList.Add(depthStencil); } } } }
/// <summary> /// Find any conflicts between the available depth/stencil formats and /// multisample types. /// </summary> private static void BuildConflictList(EnumDeviceSettingsCombo deviceCombo) { foreach (DepthFormat depthFormat in deviceCombo.depthStencilFormatList) { foreach (MultiSampleType msType in deviceCombo.multiSampleTypeList) { // Check this for conflict if (!Manager.CheckDeviceMultiSampleType((int)deviceCombo.AdapterOrdinal, deviceCombo.DeviceType, (Format)depthFormat, deviceCombo.IsWindowed, msType)) { // Add it to the list EnumDepthStencilMultisampleConflict conflict = new EnumDepthStencilMultisampleConflict(); conflict.DepthStencilFormat = depthFormat; conflict.MultisampleType = msType; deviceCombo.depthStencilConflictList.Add(conflict); } } } }
/// <summary> /// Adds all multisample types that are compatible with the device and app to /// the given device combo /// </summary> private static void BuildMultiSampleTypeList(EnumDeviceSettingsCombo deviceCombo) { foreach (MultiSampleType msType in multiSampleTypeList) { int result, quality; // Check this if (Manager.CheckDeviceMultiSampleType((int)deviceCombo.AdapterOrdinal, deviceCombo.DeviceType, deviceCombo.BackBufferFormat, deviceCombo.IsWindowed, msType, out result, out quality)) { deviceCombo.multiSampleTypeList.Add(msType); if (quality > multisampleQualityMax + 1) { quality = (int)(multisampleQualityMax + 1); } deviceCombo.multiSampleQualityList.Add(quality); } } }
/// <summary>Called when the depth stencil changes</summary> private void OnDepthStencilChanged(object sender, EventArgs e) { ComboBox cb = sender as ComboBox; DepthFormat stencilFormat = (DepthFormat)cb.GetSelectedData(); if (globalSettings.presentParams.EnableAutoDepthStencil) { globalSettings.presentParams.AutoDepthStencilFormat = stencilFormat; } EnumDeviceSettingsCombo combo = GetCurrentDeviceSettingsCombo(); // Remove all of the multisample items and add the new ones multiSampleTypeCombo.Clear(); foreach (MultiSampleType mst in combo.multiSampleTypeList) { bool conflictFound = false; foreach (EnumDepthStencilMultisampleConflict c in combo.depthStencilConflictList) { if (c.DepthStencilFormat == stencilFormat && c.MultisampleType == mst) { conflictFound = true; break; } } if (!conflictFound) { if (!multiSampleTypeCombo.ContainsItem(mst.ToString())) { multiSampleTypeCombo.AddItem(mst.ToString(), mst); } } } // Select the correct multisampling type multiSampleTypeCombo.SetSelectedByData(globalSettings.presentParams.MultiSample); OnMultisampleTypeChanged(multiSampleTypeCombo, e); }
/// <summary> /// Arbitrarily ranks device combo's /// </summary> private float RankDeviceCombo(EnumDeviceSettingsCombo deviceCombo, DeviceSettings settings, DisplayMode adapterMode) { float currentRanking = 0.0f; // Arbitrary weights. Gives preference to the ordinal, device type, and windowed const float adapterOrdinalWeight = 1000.0f; const float deviceTypeWeight = 100.0f; const float windowWeight = 10.0f; const float adapterFormatWeight = 1.0f; const float vertexProcessingWeight = 1.0f; const float resolutionWeight = 1.0f; const float backBufferFormatWeight = 1.0f; const float multiSampleWeight = 1.0f; const float depthStencilWeight = 1.0f; const float refreshRateWeight = 1.0f; const float presentIntervalWeight = 1.0f; //--------------------- // Adapter ordinal //--------------------- if (deviceCombo.AdapterOrdinal == settings.AdapterOrdinal ) currentRanking += adapterOrdinalWeight; //--------------------- // Device type //--------------------- if (deviceCombo.DeviceType == settings.DeviceType ) currentRanking += deviceTypeWeight; // Slightly prefer HAL if (deviceCombo.DeviceType == DeviceType.Hardware ) currentRanking += 0.1f; //--------------------- // Windowed //--------------------- if (deviceCombo.IsWindowed == settings.presentParams.Windowed ) currentRanking += windowWeight; //--------------------- // Adapter format //--------------------- if (deviceCombo.AdapterFormat == settings.AdapterFormat ) { currentRanking += adapterFormatWeight; } else { int bitDepthDelta = Math.Abs((int)ManagedUtility.GetColorChannelBits(deviceCombo.AdapterFormat) - (int)ManagedUtility.GetColorChannelBits(settings.AdapterFormat) ); float scale = Math.Max(0.9f - (float)bitDepthDelta*0.2f, 0); currentRanking += scale * adapterFormatWeight; } if (!deviceCombo.IsWindowed ) { // Slightly prefer when it matches the desktop format or is Format.X8R8G8B8 bool isAdapterOptimalMatch; if (ManagedUtility.GetColorChannelBits(adapterMode.Format) >= 8 ) isAdapterOptimalMatch = (deviceCombo.AdapterFormat == adapterMode.Format); else isAdapterOptimalMatch = (deviceCombo.AdapterFormat == Format.X8R8G8B8); if (isAdapterOptimalMatch ) currentRanking += 0.1f; } //--------------------- // Vertex processing //--------------------- if ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 || (settings.BehaviorFlags & CreateFlags.MixedVertexProcessing) != 0 ) { if(deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight) currentRanking += vertexProcessingWeight; } // Slightly prefer HW T&L if(deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight) currentRanking += 0.1f; //--------------------- // Resolution //--------------------- bool bResolutionFound = false; for( int idm = 0; idm < deviceCombo.adapterInformation.displayModeList.Count; idm++ ) { DisplayMode displayMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[idm]; if (displayMode.Format != deviceCombo.AdapterFormat ) continue; if (displayMode.Width == settings.presentParams.BackBufferWidth && displayMode.Height == settings.presentParams.BackBufferHeight ) bResolutionFound = true; } if (bResolutionFound ) currentRanking += resolutionWeight; //--------------------- // Back buffer format //--------------------- if (deviceCombo.BackBufferFormat == settings.presentParams.BackBufferFormat ) { currentRanking += backBufferFormatWeight; } else { int bitDepthDelta = Math.Abs((int)ManagedUtility.GetColorChannelBits(deviceCombo.BackBufferFormat) - (int)ManagedUtility.GetColorChannelBits(settings.presentParams.BackBufferFormat) ); float scale = Math.Max(0.9f - (float)bitDepthDelta*0.2f, 0); currentRanking += scale * backBufferFormatWeight; } // Check if this back buffer format is the same as // the adapter format since this is preferred. bool bAdapterMatchesBB = (deviceCombo.BackBufferFormat == deviceCombo.AdapterFormat); if (bAdapterMatchesBB ) currentRanking += 0.1f; //--------------------- // Back buffer count //--------------------- // No caps for the back buffer count //--------------------- // Multisample //--------------------- bool bMultiSampleFound = false; for( int i=0; i<deviceCombo.multiSampleTypeList.Count; i++ ) { MultiSampleType msType = (MultiSampleType)deviceCombo.multiSampleTypeList[i]; uint msQuality = (uint)(int)deviceCombo.multiSampleQualityList[i]; if (msType == settings.presentParams.MultiSample && msQuality >= settings.presentParams.MultiSampleQuality ) { bMultiSampleFound = true; break; } } if (bMultiSampleFound ) currentRanking += multiSampleWeight; //--------------------- // Swap effect //--------------------- // No caps for swap effects //--------------------- // Depth stencil //--------------------- if (deviceCombo.depthStencilFormatList.Contains( settings.presentParams.AutoDepthStencilFormat ) ) currentRanking += depthStencilWeight; //--------------------- // Present flags //--------------------- // No caps for the present flags //--------------------- // Refresh rate //--------------------- bool bRefreshFound = false; for( int idm = 0; idm < deviceCombo.adapterInformation.displayModeList.Count; idm++ ) { DisplayMode displayMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[idm]; if (displayMode.Format != deviceCombo.AdapterFormat ) continue; if (displayMode.RefreshRate == settings.presentParams.FullScreenRefreshRateInHz ) bRefreshFound = true; } if (bRefreshFound ) currentRanking += refreshRateWeight; //--------------------- // Present interval //--------------------- // If keep present interval then check that the present interval is supported by this combo if (deviceCombo.presentIntervalList.Contains( settings.presentParams.PresentationInterval ) ) currentRanking += presentIntervalWeight; return currentRanking; }
/// <summary> /// Returns false for any device combo that doesn't meet the preserve /// match options /// </summary> private bool DoesDeviceComboMatchPreserveOptions(EnumDeviceSettingsCombo deviceCombo, DeviceSettings settings, MatchOptions match) { //--------------------- // Adapter ordinal //--------------------- if (match.AdapterOrdinal == MatchType.PreserveInput && (deviceCombo.AdapterOrdinal != settings.AdapterOrdinal) ) return false; //--------------------- // Device type //--------------------- if (match.DeviceType == MatchType.PreserveInput && (deviceCombo.DeviceType != settings.DeviceType) ) return false; //--------------------- // Windowed //--------------------- if (match.Windowed == MatchType.PreserveInput && (deviceCombo.IsWindowed != settings.presentParams.Windowed) ) return false; //--------------------- // Adapter format //--------------------- if (match.AdapterFormat == MatchType.PreserveInput && (deviceCombo.AdapterFormat != settings.AdapterFormat) ) return false; //--------------------- // Vertex processing //--------------------- // If keep VP and input has HWVP, then skip if this combo doesn't have HWTL if (match.VertexProcessing == MatchType.PreserveInput && ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0) && (deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight) ) return false; //--------------------- // Resolution //--------------------- // If keep resolution then check that width and height supported by this combo if (match.Resolution == MatchType.PreserveInput ) { bool bFound = false; for( int i=0; i< deviceCombo.adapterInformation.displayModeList.Count; i++ ) { DisplayMode displayMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[i]; if (displayMode.Format != deviceCombo.AdapterFormat ) continue; // Skip this display mode if it doesn't match the combo's adapter format if (displayMode.Width == settings.presentParams.BackBufferWidth && displayMode.Height == settings.presentParams.BackBufferHeight ) { bFound = true; break; } } // If the width and height are not supported by this combo, return false if (!bFound ) return false; } //--------------------- // Back buffer format //--------------------- if (match.BackBufferFormat == MatchType.PreserveInput && deviceCombo.BackBufferFormat != settings.presentParams.BackBufferFormat ) return false; //--------------------- // Back buffer count //--------------------- // No caps for the back buffer count //--------------------- // Multisample //--------------------- if (match.MultiSample == MatchType.PreserveInput ) { bool bFound = false; for( int i=0; i<deviceCombo.multiSampleTypeList.Count; i++ ) { MultiSampleType msType = (MultiSampleType)deviceCombo.multiSampleTypeList[i]; uint msQuality = (uint)(int)deviceCombo.multiSampleQualityList[i]; if (msType == settings.presentParams.MultiSample && msQuality >= settings.presentParams.MultiSampleQuality ) { bFound = true; break; } } // If multisample type/quality not supported by this combo, then return false if (!bFound ) return false; } //--------------------- // Swap effect //--------------------- // No caps for swap effects //--------------------- // Depth stencil //--------------------- // If keep depth stencil format then check that the depth stencil format is supported by this combo if (match.DepthFormat == MatchType.PreserveInput && match.StencilFormat == MatchType.PreserveInput ) { if (settings.presentParams.AutoDepthStencilFormat != (DepthFormat)Format.Unknown && !deviceCombo.depthStencilFormatList.Contains( settings.presentParams.AutoDepthStencilFormat ) ) return false; } // If keep depth format then check that the depth format is supported by this combo if (match.DepthFormat == MatchType.PreserveInput && settings.presentParams.AutoDepthStencilFormat != DepthFormat.Unknown ) { bool bFound = false; uint depthBits = ManagedUtility.GetDepthBits( settings.presentParams.AutoDepthStencilFormat ); for( int i=0; i<deviceCombo.depthStencilFormatList.Count; i++ ) { DepthFormat depthStencilFmt = (DepthFormat)deviceCombo.depthStencilFormatList[i]; uint curDepthBits = ManagedUtility.GetDepthBits(depthStencilFmt); if (curDepthBits - depthBits == 0) bFound = true; } if (!bFound ) return false; } // If keep depth format then check that the depth format is supported by this combo if (match.StencilFormat == MatchType.PreserveInput && settings.presentParams.AutoDepthStencilFormat != DepthFormat.Unknown ) { bool bFound = false; uint stencilBits = ManagedUtility.GetStencilBits( settings.presentParams.AutoDepthStencilFormat ); for( int i=0; i<deviceCombo.depthStencilFormatList.Count; i++ ) { DepthFormat depthStencilFmt = (DepthFormat)deviceCombo.depthStencilFormatList[i]; uint curStencilBits = ManagedUtility.GetStencilBits(depthStencilFmt); if (curStencilBits - stencilBits == 0) bFound = true; } if (!bFound ) return false; } //--------------------- // Present flags //--------------------- // No caps for the present flags //--------------------- // Refresh rate //--------------------- // If keep refresh rate then check that the resolution is supported by this combo if (match.RefreshRate == MatchType.PreserveInput ) { bool bFound = false; for( int i=0; i<deviceCombo.adapterInformation.displayModeList.Count; i++ ) { DisplayMode displayMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[i]; if (displayMode.Format != deviceCombo.AdapterFormat ) continue; if (displayMode.RefreshRate == settings.presentParams.FullScreenRefreshRateInHz ) { bFound = true; break; } } // If refresh rate not supported by this combo, then return false if (!bFound ) return false; } //--------------------- // Present interval //--------------------- // If keep present interval then check that the present interval is supported by this combo if (match.PresentInterval == MatchType.PreserveInput && !deviceCombo.presentIntervalList.Contains( settings.presentParams.PresentationInterval ) ) return false; return true; }
/// <summary> /// Builds valid device settings using the match options, the input device settings, and the /// best device settings combo found. /// </summary> private DeviceSettings BuildValidDeviceSettings(EnumDeviceSettingsCombo deviceCombo, DeviceSettings settings, MatchOptions match) { DeviceSettings validSettings = new DeviceSettings(); DisplayMode adapterDesktopDisplayMode = Manager.Adapters[(int)deviceCombo.AdapterOrdinal].CurrentDisplayMode; // For each setting pick the best, taking into account the match options and // what's supported by the device //--------------------- // Adapter Ordinal //--------------------- // Just using deviceCombo.AdapterOrdinal //--------------------- // Device Type //--------------------- // Just using deviceCombo.DeviceType //--------------------- // Windowed //--------------------- // Just using deviceCombo.Windowed //--------------------- // Adapter Format //--------------------- // Just using deviceCombo.AdapterFormat //--------------------- // Vertex processing //--------------------- CreateFlags bestBehaviorFlags = 0; if (match.VertexProcessing == MatchType.PreserveInput ) { bestBehaviorFlags = settings.BehaviorFlags; } else if (match.VertexProcessing == MatchType.IgnoreInput ) { // The framework defaults to HWVP if available otherwise use SWVP if (deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight) bestBehaviorFlags |= CreateFlags.HardwareVertexProcessing; else bestBehaviorFlags |= CreateFlags.SoftwareVertexProcessing; } else { // Default to input, and fallback to SWVP if HWVP not available bestBehaviorFlags = settings.BehaviorFlags; if ((!deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight) && ( (bestBehaviorFlags & CreateFlags.HardwareVertexProcessing ) != 0 || (bestBehaviorFlags & CreateFlags.MixedVertexProcessing) != 0) ) { bestBehaviorFlags &= ~CreateFlags.HardwareVertexProcessing ; bestBehaviorFlags &= ~CreateFlags.MixedVertexProcessing; bestBehaviorFlags |= CreateFlags.SoftwareVertexProcessing; } // One of these must be selected if ((bestBehaviorFlags & CreateFlags.HardwareVertexProcessing ) == 0 && (bestBehaviorFlags & CreateFlags.MixedVertexProcessing) == 0 && (bestBehaviorFlags & CreateFlags.SoftwareVertexProcessing) == 0 ) { if (deviceCombo.deviceInformation.Caps.DeviceCaps.SupportsHardwareTransformAndLight) bestBehaviorFlags |= CreateFlags.HardwareVertexProcessing ; else bestBehaviorFlags |= CreateFlags.SoftwareVertexProcessing; } } //--------------------- // Resolution //--------------------- DisplayMode bestDisplayMode = new DisplayMode(); if (match.Resolution == MatchType.PreserveInput ) { bestDisplayMode.Width = settings.presentParams.BackBufferWidth; bestDisplayMode.Height = settings.presentParams.BackBufferHeight; } else { DisplayMode displayModeIn = new DisplayMode(); if (match.Resolution == MatchType.ClosestToInput && (settings.presentParams.BackBufferWidth != 0 && settings.presentParams.BackBufferWidth != 0) ) { displayModeIn.Width = settings.presentParams.BackBufferWidth; displayModeIn.Height = settings.presentParams.BackBufferHeight; } else // if (match.Resolution == MatchType.IgnoreInput ) { if (deviceCombo.IsWindowed ) { // The framework defaults to 640x480 for windowed displayModeIn.Width = DefaultSizeWidth; displayModeIn.Height = DefaultSizeHeight; } else { // The framework defaults to desktop resolution for fullscreen to try to avoid slow mode change displayModeIn.Width = adapterDesktopDisplayMode.Width; displayModeIn.Height = adapterDesktopDisplayMode.Height; } } // Call a helper function to find the closest valid display mode to the optimal bestDisplayMode = FindValidResolution(deviceCombo, displayModeIn); } //--------------------- // Back Buffer Format //--------------------- // Just using deviceCombo.BackBufferFormat //--------------------- // Back buffer count //--------------------- uint bestBackBufferCount; if (match.BackBufferCount == MatchType.PreserveInput ) { bestBackBufferCount = (uint)settings.presentParams.BackBufferCount; } else if (match.BackBufferCount == MatchType.IgnoreInput ) { // The framework defaults to triple buffering bestBackBufferCount = 2; } else // if (match.BackBufferCount == MatchType.ClosestToInput ) { bestBackBufferCount = (uint)settings.presentParams.BackBufferCount; if (bestBackBufferCount > 3 ) bestBackBufferCount = 3; if (bestBackBufferCount < 1 ) bestBackBufferCount = 1; } //--------------------- // Multisample //--------------------- MultiSampleType bestMultiSampleType; uint bestMultiSampleQuality; if (settings.presentParams.SwapEffect != SwapEffect.Discard) { // Swap effect is not set to discard so multisampling has to off bestMultiSampleType = MultiSampleType.None; bestMultiSampleQuality = 0; } else { if (match.BackBufferCount == MatchType.PreserveInput ) { bestMultiSampleType = settings.presentParams.MultiSample; bestMultiSampleQuality = (uint)settings.presentParams.MultiSampleQuality; } else if (match.BackBufferCount == MatchType.IgnoreInput ) { // Default to no multisampling (always supported) bestMultiSampleType = MultiSampleType.None; bestMultiSampleQuality = 0; } else if (match.BackBufferCount == MatchType.ClosestToInput ) { // Default to no multisampling (always supported) bestMultiSampleType = MultiSampleType.None; bestMultiSampleQuality = 0; for (int i = 0; i < deviceCombo.multiSampleTypeList.Count; i++) { MultiSampleType tempType = (MultiSampleType)deviceCombo.multiSampleTypeList[i]; uint tempQuality = (uint)(int)deviceCombo.multiSampleQualityList[i]; // Check whether supported type is closer to the input than our current best if (Math.Abs((int)tempType - (int)settings.presentParams.MultiSample) < Math.Abs((int)bestMultiSampleType - (int)settings.presentParams.MultiSample) ) { bestMultiSampleType = tempType; bestMultiSampleQuality = (uint)Math.Min(tempQuality-1, settings.presentParams.MultiSampleQuality); } } } else // Error case { // Default to no multisampling (always supported) bestMultiSampleType = MultiSampleType.None; bestMultiSampleQuality = 0; } } //--------------------- // Swap effect //--------------------- SwapEffect bestSwapEffect; if (match.SwapEffect == MatchType.PreserveInput ) { bestSwapEffect = settings.presentParams.SwapEffect; } else if (match.SwapEffect == MatchType.IgnoreInput ) { bestSwapEffect = SwapEffect.Discard; } else // if (match.SwapEffect == MatchType.ClosestToInput ) { bestSwapEffect = settings.presentParams.SwapEffect; // Swap effect has to be one of these 3 if (bestSwapEffect != SwapEffect.Discard && bestSwapEffect != SwapEffect.Flip && bestSwapEffect != SwapEffect.Copy ) { bestSwapEffect = SwapEffect.Discard; } } //--------------------- // Depth stencil //--------------------- DepthFormat bestDepthStencilFormat; bool bestEnableAutoDepthStencil; int[] depthStencilRanking = new int[deviceCombo.depthStencilFormatList.Count]; uint backBufferBitDepth = ManagedUtility.GetColorChannelBits( deviceCombo.BackBufferFormat ); uint inputDepthBitDepth = ManagedUtility.GetDepthBits( settings.presentParams.AutoDepthStencilFormat ); for( int i=0; i<deviceCombo.depthStencilFormatList.Count; i++ ) { DepthFormat curDepthStencilFmt = (DepthFormat)deviceCombo.depthStencilFormatList[i]; uint curDepthBitDepth = ManagedUtility.GetDepthBits( curDepthStencilFmt ); int ranking; if (match.DepthFormat == MatchType.PreserveInput ) { // Need to match bit depth of input if(curDepthBitDepth == inputDepthBitDepth) ranking = 0; else ranking = 10000; } else if (match.DepthFormat == MatchType.IgnoreInput ) { // Prefer match of backbuffer bit depth ranking = Math.Abs((int)curDepthBitDepth - (int)(backBufferBitDepth*4)); } else // if (match.DepthFormat == MatchType.ClosestToInput ) { // Prefer match of input depth format bit depth ranking = Math.Abs((int)curDepthBitDepth - (int)inputDepthBitDepth); } depthStencilRanking[i] = ranking; } uint inputStencilBitDepth = ManagedUtility.GetStencilBits( settings.presentParams.AutoDepthStencilFormat ); for( int i=0; i<deviceCombo.depthStencilFormatList.Count; i++ ) { DepthFormat curDepthStencilFmt = (DepthFormat)deviceCombo.depthStencilFormatList[i]; int ranking = depthStencilRanking[i]; uint curStencilBitDepth = ManagedUtility.GetStencilBits( curDepthStencilFmt ); if (match.StencilFormat == MatchType.PreserveInput ) { // Need to match bit depth of input if(curStencilBitDepth == inputStencilBitDepth) ranking += 0; else ranking += 10000; } else if (match.StencilFormat == MatchType.IgnoreInput ) { // Prefer 0 stencil bit depth ranking += (int)curStencilBitDepth; } else // if (match.StencilFormat == MatchType.ClosestToInput ) { // Prefer match of input stencil format bit depth ranking += Math.Abs((int)curStencilBitDepth - (int)inputStencilBitDepth); } depthStencilRanking[i] = ranking; } int bestRanking = 100000; int bestIndex = -1; for( int i=0; i<depthStencilRanking.Length; i++ ) { if (depthStencilRanking[i] < bestRanking ) { bestRanking = depthStencilRanking[i]; bestIndex = i; } } if (bestIndex >= 0 ) { bestDepthStencilFormat = (DepthFormat)deviceCombo.depthStencilFormatList[bestIndex]; bestEnableAutoDepthStencil = true; } else { bestDepthStencilFormat = DepthFormat.Unknown; bestEnableAutoDepthStencil = false; } //--------------------- // Present flags //--------------------- PresentFlag bestPresentFlag; if (match.PresentFlags == MatchType.PreserveInput ) { bestPresentFlag = settings.presentParams.PresentFlag; } else if (match.PresentFlags == MatchType.IgnoreInput ) { bestPresentFlag = 0; if (bestEnableAutoDepthStencil ) bestPresentFlag = PresentFlag.DiscardDepthStencil; } else // if (match.PresentFlags == MatchType.ClosestToInput ) { bestPresentFlag = settings.presentParams.PresentFlag; if (bestEnableAutoDepthStencil ) bestPresentFlag |= PresentFlag.DiscardDepthStencil; } //--------------------- // Refresh rate //--------------------- if (deviceCombo.IsWindowed ) { // Must be 0 for windowed bestDisplayMode.RefreshRate = 0; } else { if (match.RefreshRate == MatchType.PreserveInput ) { bestDisplayMode.RefreshRate = settings.presentParams.FullScreenRefreshRateInHz; } else { uint refreshRateMatch; if (match.RefreshRate == MatchType.ClosestToInput ) { refreshRateMatch = (uint)settings.presentParams.FullScreenRefreshRateInHz; } else // if (match.RefreshRate == MatchType.IgnoreInput ) { refreshRateMatch = (uint)adapterDesktopDisplayMode.RefreshRate; } bestDisplayMode.RefreshRate = 0; if (refreshRateMatch != 0 ) { int bestRefreshRanking = 100000; for( int iDisplayMode=0; iDisplayMode<deviceCombo.adapterInformation.displayModeList.Count; iDisplayMode++ ) { DisplayMode displayMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[iDisplayMode]; if (displayMode.Format != deviceCombo.AdapterFormat || displayMode.Height != bestDisplayMode.Height || displayMode.Width != bestDisplayMode.Width ) continue; // Skip display modes that don't match // Find the delta between the current refresh rate and the optimal refresh rate int currentRefreshRanking = Math.Abs((int)displayMode.RefreshRate - (int)refreshRateMatch); if (currentRefreshRanking < bestRefreshRanking ) { bestDisplayMode.RefreshRate = displayMode.RefreshRate; bestRefreshRanking = currentRefreshRanking; // Stop if perfect match found if (bestRefreshRanking == 0 ) break; } } } } } //--------------------- // Present interval //--------------------- PresentInterval bestPresentInterval; if (match.PresentInterval == MatchType.PreserveInput ) { bestPresentInterval = settings.presentParams.PresentationInterval; } else if (match.PresentInterval == MatchType.IgnoreInput ) { if (deviceCombo.IsWindowed ) { // For windowed, the framework defaults to PresentInterval.Immediate // which will wait not for the vertical retrace period to prevent tearing, // but may introduce tearing bestPresentInterval = PresentInterval.Immediate; } else { // For full screen, the framework defaults to PresentInterval.Default // which will wait for the vertical retrace period to prevent tearing bestPresentInterval = PresentInterval.Default; } } else // if (match.PresentInterval == MatchType.ClosestToInput ) { if (deviceCombo.presentIntervalList.Contains( settings.presentParams.PresentationInterval ) ) { bestPresentInterval = settings.presentParams.PresentationInterval; } else { if (deviceCombo.IsWindowed ) bestPresentInterval = PresentInterval.Immediate; else bestPresentInterval = PresentInterval.Default; } } // Fill the device settings struct validSettings.AdapterOrdinal = deviceCombo.AdapterOrdinal; validSettings.DeviceType = deviceCombo.DeviceType; validSettings.AdapterFormat = deviceCombo.AdapterFormat; validSettings.BehaviorFlags = bestBehaviorFlags; validSettings.presentParams = new PresentParameters(); validSettings.presentParams.BackBufferWidth = bestDisplayMode.Width; validSettings.presentParams.BackBufferHeight = bestDisplayMode.Height; validSettings.presentParams.BackBufferFormat = deviceCombo.BackBufferFormat; validSettings.presentParams.BackBufferCount = (int)bestBackBufferCount; validSettings.presentParams.MultiSample = bestMultiSampleType; validSettings.presentParams.MultiSampleQuality = (int)bestMultiSampleQuality; validSettings.presentParams.SwapEffect = bestSwapEffect; validSettings.presentParams.DeviceWindow = deviceCombo.IsWindowed ? State.WindowDeviceWindowed : State.WindowDeviceFullScreen; validSettings.presentParams.Windowed = deviceCombo.IsWindowed; validSettings.presentParams.EnableAutoDepthStencil = bestEnableAutoDepthStencil; validSettings.presentParams.AutoDepthStencilFormat = bestDepthStencilFormat; validSettings.presentParams.PresentFlag = bestPresentFlag; validSettings.presentParams.FullScreenRefreshRateInHz = bestDisplayMode.RefreshRate; validSettings.presentParams.PresentationInterval = bestPresentInterval; validSettings.presentParams.ForceNoMultiThreadedFlag = true; return validSettings; }
/// <summary> /// Enumerates device combinations for a particular device. /// </summary> private static void EnumerateDeviceCombos(EnumAdapterInformation adapterInfo, EnumDeviceInformation deviceInfo, ArrayList adapterFormatList) { // Find out which adapter formats are supported by this device foreach(Format adapterFormat in adapterFormatList) { for(int i = 0; i < backbufferFormatsArray.Length; i++) { // Go through each windowed mode for (int windowedIndex = 0; windowedIndex < 2; windowedIndex++) { bool isWindowedIndex = (windowedIndex == 1); if ((!isWindowedIndex) && (adapterInfo.displayModeList.Count == 0)) continue; // Nothing here if (!Manager.CheckDeviceType((int)adapterInfo.AdapterOrdinal, deviceInfo.DeviceType, adapterFormat, backbufferFormatsArray[i], isWindowedIndex)) continue; // Unsupported // Do we require post pixel shader blending? if (isPostPixelShaderBlendingRequired) { // If the backbuffer format doesn't support Usage.QueryPostPixelShaderBlending // then alpha test, pixel fog, render-target blending, color write enable, and dithering // are not supported. if (!Manager.CheckDeviceFormat((int)adapterInfo.AdapterOrdinal, deviceInfo.DeviceType, adapterFormat, Usage.QueryPostPixelShaderBlending, ResourceType.Textures, backbufferFormatsArray[i])) continue; // Unsupported } // If an application callback function has been provided, make sure this device // is acceptable to the app. if (deviceCreationInterface != null) { if (!deviceCreationInterface.IsDeviceAcceptable(deviceInfo.Caps, adapterFormat, backbufferFormatsArray[i],isWindowedIndex)) continue; // Application doesn't like this device } // At this point, we have an adapter/device/adapterformat/backbufferformat/iswindowed // DeviceCombo that is supported by the system and acceptable to the app. We still // need to find one or more suitable depth/stencil buffer format, // multisample type, and present interval. EnumDeviceSettingsCombo deviceCombo = new EnumDeviceSettingsCombo(); // Store the information deviceCombo.AdapterOrdinal = adapterInfo.AdapterOrdinal; deviceCombo.DeviceType = deviceInfo.DeviceType; deviceCombo.AdapterFormat = adapterFormat; deviceCombo.BackBufferFormat = backbufferFormatsArray[i]; deviceCombo.IsWindowed = isWindowedIndex; // Build the depth stencil format and multisample type list BuildDepthStencilFormatList(deviceCombo); BuildMultiSampleTypeList(deviceCombo); if (deviceCombo.multiSampleTypeList.Count == 0) { // Nothing to do continue; } // Build the conflict and present lists BuildConflictList(deviceCombo); BuildPresentIntervalList(deviceInfo, deviceCombo); deviceCombo.adapterInformation = adapterInfo; deviceCombo.deviceInformation = deviceInfo; // Add the combo to the list of devices deviceInfo.deviceSettingsList.Add(deviceCombo); } } } }
/// <summary> /// Adds all multisample types that are compatible with the device and app to /// the given device combo /// </summary> private static void BuildMultiSampleTypeList(EnumDeviceSettingsCombo deviceCombo) { foreach(MultiSampleType msType in multiSampleTypeList) { int result, quality; // Check this if (Manager.CheckDeviceMultiSampleType((int)deviceCombo.AdapterOrdinal, deviceCombo.DeviceType, deviceCombo.BackBufferFormat, deviceCombo.IsWindowed, msType, out result, out quality)) { deviceCombo.multiSampleTypeList.Add(msType); if (quality > multisampleQualityMax + 1) quality = (int)(multisampleQualityMax + 1); deviceCombo.multiSampleQualityList.Add(quality); } } }
/// <summary> /// Adds all depth/stencil formats that are compatible with the device /// and application to the given device combo /// </summary> private static void BuildDepthStencilFormatList(EnumDeviceSettingsCombo deviceCombo) { foreach(DepthFormat depthStencil in depthStencilPossibleList) { if (Manager.CheckDeviceFormat((int)deviceCombo.AdapterOrdinal, deviceCombo.DeviceType, deviceCombo.AdapterFormat, Usage.DepthStencil, ResourceType.Surface, depthStencil)) { // This can be used as a depth stencil, make sure it matches if (Manager.CheckDepthStencilMatch((int)deviceCombo.AdapterOrdinal, deviceCombo.DeviceType, deviceCombo.AdapterFormat, deviceCombo.BackBufferFormat, depthStencil)) { // Yup, add it deviceCombo.depthStencilFormatList.Add(depthStencil); } } } }
/// <summary> /// Find any conflicts between the available depth/stencil formats and /// multisample types. /// </summary> private static void BuildConflictList(EnumDeviceSettingsCombo deviceCombo) { foreach(DepthFormat depthFormat in deviceCombo.depthStencilFormatList) { foreach(MultiSampleType msType in deviceCombo.multiSampleTypeList) { // Check this for conflict if (!Manager.CheckDeviceMultiSampleType((int)deviceCombo.AdapterOrdinal, deviceCombo.DeviceType, (Format)depthFormat, deviceCombo.IsWindowed, msType)) { // Add it to the list EnumDepthStencilMultisampleConflict conflict = new EnumDepthStencilMultisampleConflict(); conflict.DepthStencilFormat = depthFormat; conflict.MultisampleType = msType; deviceCombo.depthStencilConflictList.Add(conflict); } } } }
/// <summary> /// Adds all present intervals that are compatible with the device and app /// to the given device combo /// </summary> private static void BuildPresentIntervalList(EnumDeviceInformation deviceInfo, EnumDeviceSettingsCombo deviceCombo) { for (int i = 0; i < presentIntervalList.Count; i++) { PresentInterval pi = (PresentInterval)presentIntervalList[i]; if (deviceCombo.IsWindowed) { if ((pi == PresentInterval.Two) || (pi == PresentInterval.Three) || (pi == PresentInterval.Four)) { // These intervals are never supported in windowed mode continue; } } // Not that PresentInterval.Default is zero so you can't do a bitwise // check for it, it's always available if ((pi == PresentInterval.Default) || ((deviceInfo.Caps.PresentationIntervals & pi) != 0)) { deviceCombo.presentIntervalList.Add(pi); } } }
/// <summary> /// public helper function to find the closest allowed display mode to the optimal /// </summary> private DisplayMode FindValidResolution(EnumDeviceSettingsCombo deviceCombo, DisplayMode displayMode) { DisplayMode bestDisplayMode = displayMode; if (deviceCombo.IsWindowed) { // Get the desktop resolution of the current monitor to use to keep the window // in a reasonable size in the desktop's // This isn't the same as the current resolution from GetAdapterDisplayMode // since the device might be fullscreen EnumAdapterInformation adapterInfo = Enumeration.GetAdapterInformation(deviceCombo.AdapterOrdinal); // Find the right screen System.Windows.Forms.Screen displayScreen = null; string adapterName = adapterInfo.AdapterInformation.DeviceName.ToLower(); foreach(System.Windows.Forms.Screen s in System.Windows.Forms.Screen.AllScreens) { string deviceName = s.DeviceName.ToLower(); // For some reason the device name has null characters in it. Remove them if (deviceName.IndexOf("\0") > 0) { deviceName = deviceName.Substring(0, deviceName.IndexOf("\0")); } if (deviceName == adapterName) { // Found the correct screen displayScreen = s; break; } } System.Diagnostics.Debug.Assert(displayScreen != null, "We should have found the screen by now."); // For windowed mode, just keep it something reasonable within the size // of the working area of the desktop if (bestDisplayMode.Width > displayScreen.WorkingArea.Width ) bestDisplayMode.Width = displayScreen.WorkingArea.Width; if (bestDisplayMode.Height > displayScreen.WorkingArea.Height ) bestDisplayMode.Height = displayScreen.WorkingArea.Height; } else { int bestRanking = 100000; int currentRanking; for( int iDisplayMode=0; iDisplayMode<deviceCombo.adapterInformation.displayModeList.Count; iDisplayMode++ ) { DisplayMode storedMode = (DisplayMode)deviceCombo.adapterInformation.displayModeList[iDisplayMode]; // Skip display modes that don't match the combo's adapter format if (storedMode.Format != deviceCombo.AdapterFormat ) continue; // Find the delta between the current width/height and the optimal width/height currentRanking = Math.Abs((int)storedMode.Width - (int)displayMode.Width) + Math.Abs((int)storedMode.Height- (int)displayMode.Height); if (currentRanking < bestRanking ) { bestDisplayMode = displayMode; bestRanking = currentRanking; // Stop if perfect match found if (bestRanking == 0 ) break; } } // Were any found? if (bestDisplayMode.Width == 0 ) { throw new NoCompatibleDevicesException(); } } return bestDisplayMode; }
/// <summary> /// Adds all present intervals that are compatible with the device and app /// to the given device combo /// </summary> private static void BuildPresentIntervalList(EnumDeviceInformation deviceInfo, EnumDeviceSettingsCombo deviceCombo) { for (int i = 0; i < presentIntervalList.Count; i++) { PresentInterval pi = (PresentInterval)presentIntervalList[i]; if (deviceCombo.IsWindowed) { if ( (pi == PresentInterval.Two) || (pi == PresentInterval.Three) || (pi == PresentInterval.Four) ) { // These intervals are never supported in windowed mode continue; } } // Not that PresentInterval.Default is zero so you can't do a bitwise // check for it, it's always available if ( (pi == PresentInterval.Default) || ((deviceInfo.Caps.PresentationIntervals & pi) != 0)) { deviceCombo.presentIntervalList.Add(pi); } } }
/// <summary> /// This function tries to find valid device settings based upon the input device settings /// struct and the match options. For each device setting a match option in the /// MatchOptions struct specifies how the function makes decisions. For example, if /// the caller wants a hardware device with a back buffer format of A2B10G10R10 but the /// hardware device on the system does not support A2B10G10R10 however a reference device is /// installed that does, then the function has a choice to either use the reference device /// or to change to a back buffer format to compatible with the hardware device. The match options lets the /// caller control how these choices are made. /// /// Each match option must be one of the following types: /// MatchType.IgnoreInput: Uses the closest valid value to a default /// MatchType.PreserveInput: Uses the input without change, but may cause no valid device to be found /// MatchType.ClosestToInput: Uses the closest valid value to the input /// </summary> private DeviceSettings FindValidDeviceSettings(DeviceSettings settings, MatchOptions match) { // Build an optimal device settings structure based upon the match // options. If the match option is set to ignore, then a optimal default value is used. // The default value may not exist on the system, but later this will be taken // into account. DeviceSettings optimalSettings = BuildOptimalDeviceSettings(settings, match); float bestRanking = -1.0f; EnumDeviceSettingsCombo bestDeviceSettingsCombo = new EnumDeviceSettingsCombo(); // Find the best combination of: // Adapter Ordinal // Device Type // Adapter Format // Back Buffer Format // Windowed // given what's available on the system and the match options combined with the device settings input. // This combination of settings is encapsulated by the EnumDeviceSettingsCombo class. DisplayMode adapterDesktopDisplayMode; for (int iAdapter = 0; iAdapter < Enumeration.AdapterInformationList.Count; iAdapter++) { EnumAdapterInformation adapterInfo = Enumeration.AdapterInformationList[iAdapter] as EnumAdapterInformation; // Get the desktop display mode of the adapter adapterDesktopDisplayMode = Manager.Adapters[(int)adapterInfo.AdapterOrdinal].CurrentDisplayMode; // Enum all the device types supported by this adapter to find the best device settings for (int iDeviceInfo = 0; iDeviceInfo < adapterInfo.deviceInfoList.Count; iDeviceInfo++) { EnumDeviceInformation deviceInfo = adapterInfo.deviceInfoList[iDeviceInfo] as EnumDeviceInformation; for (int iDeviceCombo = 0; iDeviceCombo<deviceInfo.deviceSettingsList.Count; iDeviceCombo++) { EnumDeviceSettingsCombo deviceSettings = deviceInfo.deviceSettingsList[iDeviceCombo] as EnumDeviceSettingsCombo; // If windowed mode the adapter format has to be the same as the desktop // display mode format so skip any that don't match if (deviceSettings.IsWindowed && (deviceSettings.AdapterFormat != adapterDesktopDisplayMode.Format)) continue; // Skip any combo that doesn't meet the preserve match options if(!DoesDeviceComboMatchPreserveOptions(deviceSettings, settings, match)) continue; // Get a ranking number that describes how closely this device combo matches the optimal combo float curRanking = RankDeviceCombo(deviceSettings, optimalSettings, adapterDesktopDisplayMode); // If this combo better matches the input device settings then save it if (curRanking > bestRanking ) { bestDeviceSettingsCombo = deviceSettings; bestRanking = curRanking; } } } } // If no best device combination was found then fail if (bestRanking == -1.0f) { throw new NoCompatibleDevicesException(); } // Using the best device settings combo found, build valid device settings taking heed of // the match options and the input device settings return BuildValidDeviceSettings(bestDeviceSettingsCombo, settings, match); }
/// <summary> /// Enumerates device combinations for a particular device. /// </summary> private static void EnumerateDeviceCombos(EnumAdapterInformation adapterInfo, EnumDeviceInformation deviceInfo, ArrayList adapterFormatList) { // Find out which adapter formats are supported by this device foreach (Format adapterFormat in adapterFormatList) { for (int i = 0; i < backbufferFormatsArray.Length; i++) { // Go through each windowed mode for (int windowedIndex = 0; windowedIndex < 2; windowedIndex++) { bool isWindowedIndex = (windowedIndex == 1); if ((!isWindowedIndex) && (adapterInfo.displayModeList.Count == 0)) { continue; // Nothing here } if (!Manager.CheckDeviceType((int)adapterInfo.AdapterOrdinal, deviceInfo.DeviceType, adapterFormat, backbufferFormatsArray[i], isWindowedIndex)) { continue; // Unsupported } // Do we require post pixel shader blending? if (isPostPixelShaderBlendingRequired) { // If the backbuffer format doesn't support Usage.QueryPostPixelShaderBlending // then alpha test, pixel fog, render-target blending, color write enable, and dithering // are not supported. if (!Manager.CheckDeviceFormat((int)adapterInfo.AdapterOrdinal, deviceInfo.DeviceType, adapterFormat, Usage.QueryPostPixelShaderBlending, ResourceType.Textures, backbufferFormatsArray[i])) { continue; // Unsupported } } // If an application callback function has been provided, make sure this device // is acceptable to the app. if (deviceCreationInterface != null) { if (!deviceCreationInterface.IsDeviceAcceptable(deviceInfo.Caps, adapterFormat, backbufferFormatsArray[i], isWindowedIndex)) { continue; // Application doesn't like this device } } // At this point, we have an adapter/device/adapterformat/backbufferformat/iswindowed // DeviceCombo that is supported by the system and acceptable to the app. We still // need to find one or more suitable depth/stencil buffer format, // multisample type, and present interval. EnumDeviceSettingsCombo deviceCombo = new EnumDeviceSettingsCombo(); // Store the information deviceCombo.AdapterOrdinal = adapterInfo.AdapterOrdinal; deviceCombo.DeviceType = deviceInfo.DeviceType; deviceCombo.AdapterFormat = adapterFormat; deviceCombo.BackBufferFormat = backbufferFormatsArray[i]; deviceCombo.IsWindowed = isWindowedIndex; // Build the depth stencil format and multisample type list BuildDepthStencilFormatList(deviceCombo); BuildMultiSampleTypeList(deviceCombo); if (deviceCombo.multiSampleTypeList.Count == 0) { // Nothing to do continue; } // Build the conflict and present lists BuildConflictList(deviceCombo); BuildPresentIntervalList(deviceInfo, deviceCombo); deviceCombo.adapterInformation = adapterInfo; deviceCombo.deviceInformation = deviceInfo; // Add the combo to the list of devices deviceInfo.deviceSettingsList.Add(deviceCombo); } } } }