/// <summary>Clone this object</summary> public DeviceSettings Clone() { DeviceSettings clonedObject = new DeviceSettings(); clonedObject.presentParams = (PresentParameters)this.presentParams.Clone(); clonedObject.AdapterFormat = this.AdapterFormat; clonedObject.AdapterOrdinal = this.AdapterOrdinal; clonedObject.BehaviorFlags = this.BehaviorFlags; clonedObject.DeviceType = this.DeviceType; return clonedObject; }
/// <summary> /// This callback function is called immediately before a device is created to allow the /// application to modify the device settings. The supplied settings parameter /// contains the settings that the framework has selected for the new device, and the /// application can make any desired changes directly to this structure. Note however that /// the sample framework will not correct invalid device settings so care must be taken /// to return valid device settings, otherwise creating the Device will fail. /// </summary> public void ModifyDeviceSettings(DeviceSettings settings, Caps caps) { // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW // then switch to SWVP. if ( (!caps.DeviceCaps.SupportsHardwareTransformAndLight) || (caps.VertexShaderVersion < new Version(1,1)) ) { settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing; } else { settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing; } // This application is designed to work on a pure device by not using // any get methods, so create a pure device if supported and using HWVP. if ( (caps.DeviceCaps.SupportsPureDevice) && ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 ) ) settings.BehaviorFlags |= CreateFlags.PureDevice; // Debugging vertex shaders requires either REF or software vertex processing // and debugging pixel shaders requires REF. #if(DEBUG_VS) if (settings.DeviceType != DeviceType.Reference ) { settings.BehaviorFlags &= ~CreateFlags.HardwareVertexProcessing; settings.BehaviorFlags |= CreateFlags.SoftwareVertexProcessing; } #endif #if(DEBUG_PS) settings.DeviceType = DeviceType.Reference; #endif // For the first device created if its a REF device, optionally display a warning dialog box if (settings.DeviceType == DeviceType.Reference) { Utility.DisplaySwitchingToRefWarning(Framework, "Simbiosis"); } }
/// <summary> /// Tells the framework to change to a device created from the passed in device settings /// If CreateWindow() has not already been called, it will call it with the /// default parameters. Instead of calling this, you can call CreateDevice() /// or SetDevice() /// </summary> public void CreateDeviceFromSettings(DeviceSettings deviceSettings) { CreateDeviceFromSettings(deviceSettings, false); }
/// <summary> /// Tells the framework to change to a device created from the passed in device settings /// If CreateWindow() has not already been called, it will call it with the /// default parameters. Instead of calling this, you can call CreateDevice() /// or SetDevice() /// </summary> public void CreateDeviceFromSettings(DeviceSettings deviceSettings, bool preserveInput) { // Set the state since this was called State.WasDeviceCreateCalled = true; // Was the window created? If not, create it now if (!State.WasWindowCreated) { // If CreateWindow or SetWindow was already called and failed, then fail again. if (State.WasWindowCreateCalled) { throw new InvalidOperationException("CreateWindow was already called and failed."); } // Create a default window CreateWindow("Direct3D Window", null, null, -1, -1); } if (!preserveInput) { // If not preserving the input, the find the closest valid to it MatchOptions match = new MatchOptions(); match.AdapterOrdinal = MatchType.ClosestToInput; match.DeviceType = MatchType.ClosestToInput; match.Windowed = MatchType.ClosestToInput; match.AdapterFormat = MatchType.ClosestToInput; match.VertexProcessing = MatchType.ClosestToInput; match.Resolution = MatchType.ClosestToInput; match.BackBufferFormat = MatchType.ClosestToInput; match.BackBufferCount = MatchType.ClosestToInput; match.MultiSample = MatchType.ClosestToInput; match.SwapEffect = MatchType.ClosestToInput; match.DepthFormat = MatchType.ClosestToInput; match.StencilFormat = MatchType.ClosestToInput; match.PresentFlags = MatchType.ClosestToInput; match.RefreshRate = MatchType.ClosestToInput; match.PresentInterval = MatchType.ClosestToInput; try { deviceSettings = FindValidDeviceSettings(deviceSettings, match); } catch(Exception e) { // Display any error message DisplayErrorMessage(e); throw; } // Change to a Direct3D device created from the new device settings. // If there is an existing device, then either reset or recreate the scene ChangeDevice(deviceSettings, null, false); } }
/// <summary> /// Updates the device settings struct based on the cmd line args. /// </summary> private void UpdateDeviceSettingsWithOverrides(ref DeviceSettings settings) { if (State.OverrideAdapterOrdinal != -1) settings.AdapterOrdinal = (uint)State.OverrideAdapterOrdinal; if (State.IsOverridingFullScreen) settings.presentParams.Windowed = false; if (State.IsOverridingWindowed) settings.presentParams.Windowed = true; if (State.IsOverridingForceReference) settings.DeviceType = DeviceType.Reference; else if (State.IsOverridingForceHardware) settings.DeviceType = DeviceType.Hardware; if (State.OverrideWidth != 0) settings.presentParams.BackBufferWidth = State.OverrideWidth; if (State.OverrideHeight != 0) settings.presentParams.BackBufferHeight = State.OverrideHeight; if (State.IsOverridingForcePureHardwareVertexProcessing) { settings.BehaviorFlags &= ~CreateFlags.SoftwareVertexProcessing; settings.BehaviorFlags |= CreateFlags.HardwareVertexProcessing; settings.BehaviorFlags |= CreateFlags.PureDevice; } else if (State.IsOverridingForceHardwareVertexProcessing) { settings.BehaviorFlags &= ~CreateFlags.SoftwareVertexProcessing; settings.BehaviorFlags &= ~CreateFlags.PureDevice; settings.BehaviorFlags |= CreateFlags.HardwareVertexProcessing; } else if (State.IsOverridingForceSoftwareVertexProcessing) { settings.BehaviorFlags &= ~CreateFlags.HardwareVertexProcessing; settings.BehaviorFlags &= ~CreateFlags.PureDevice; settings.BehaviorFlags |= CreateFlags.SoftwareVertexProcessing; } }
/// <summary> /// Change to a Direct3D device created from the device settings or passed in. /// The framework will only reset if the device is similar to the previous device /// otherwise it will cleanup the previous device (if there is one) and recreate the /// scene using the app's device callbacks. /// </summary> private void ChangeDevice(DeviceSettings newDeviceSettings, Device deviceFromApp, bool forceRecreate) { // Nothing to do if the framework is already disposed if (isDisposed) return; // First store the current device settings DeviceSettings oldSettings = null; if (State.CurrentDeviceSettings != null) oldSettings = State.CurrentDeviceSettings.Clone(); // Pause the application Pause(true, true); // When a size message is received, it calls HandlePossibleSizeChange(). // A size message might be sent when adjusting the window, so tell // HandlePossibleSizeChange() to ignore size changes temporarily State.AreSizeChangesIgnored = true; // Only apply the cmd line overrides if this is the first device created // and SetDevice() isn't used if ( (deviceFromApp == null) && (oldSettings == null) ) { // Updates the device settings struct based on the cmd line args. // Warning: if the device doesn't support these new settings then CreateDevice() will fail. UpdateDeviceSettingsWithOverrides(ref newDeviceSettings); } // If windowed, then update the window client rect and window bounds rect // with the new pp.BackBufferWidth & pp.BackBufferHeight // The window will be resized after the device is reset/creeted if (newDeviceSettings.presentParams.Windowed) { // Don't allow smaller than what's used in minimum window size // otherwise the window size will be different than the backbuffer size if (newDeviceSettings.presentParams.BackBufferWidth < MinimumWindowSizeX) newDeviceSettings.presentParams.BackBufferWidth = MinimumWindowSizeX; if (newDeviceSettings.presentParams.BackBufferHeight < MinimumWindowSizeY) newDeviceSettings.presentParams.BackBufferHeight = MinimumWindowSizeY; if (State.WindowFocus != null) { // Create a new client rectangle of the correct size System.Drawing.Rectangle windowClient = State.ClientRectangle; windowClient.Size = new System.Drawing.Size(newDeviceSettings.presentParams.BackBufferWidth, newDeviceSettings.presentParams.BackBufferHeight); State.ClientRectangle = windowClient; // Store this for resizing later State.WindowBoundsRectangle = WindowFocus.Bounds;; } } // Set the new device settings State.CurrentDeviceSettings = newDeviceSettings; // If AdapterOrdinal and DeviceType are the same, we can just do a Reset(). // If they've changed, we need to do a complete device tear down/rebuild. // Also only allow a reset if deviceFromApp is the same as the current device if( !forceRecreate && (deviceFromApp == null || deviceFromApp == State.Device) && oldSettings != null && oldSettings.AdapterOrdinal == newDeviceSettings.AdapterOrdinal && oldSettings.DeviceType == newDeviceSettings.DeviceType && oldSettings.BehaviorFlags == newDeviceSettings.BehaviorFlags ) { try { // Reset the Direct3D device Reset3DEnvironment(); } catch { // The reset has failed, the device is lost Pause (false, false); State.IsDeviceLost = true; } } else { // Recreate the device if (oldSettings != null) { // The adapter and device type don't match so // cleanup and create the 3D device again Cleanup3DEnvironment(false); } Device device = deviceFromApp; // Only create a Direct3D device if one hasn't been supplied by the app if (deviceFromApp == null) { try { device = new Device((int)newDeviceSettings.AdapterOrdinal, newDeviceSettings.DeviceType, State.WindowFocus, newDeviceSettings.BehaviorFlags, newDeviceSettings.presentParams); } catch (Exception e) { // There was an error creating the device Pause(false, false); CreatingDeviceException cde = new CreatingDeviceException(e); DisplayErrorMessage(cde); throw; } } // Hook the device lost/reset events device.DeviceLost += new EventHandler(OnDeviceLost); device.DeviceReset += new EventHandler(OnDeviceReset); device.Disposing += new EventHandler(OnDeviceDisposing); // Store the device State.Device = device; // Now that the device is created, update the window and misc settings and // call the app's DeviceCreated and DeviceReset callbacks. try { Initialize3DEnvironment(); } catch { Pause(false, false); throw; } // Update the device stats text Enumeration.Enumerate(null); EnumAdapterInformation adapterInfo = Enumeration.GetAdapterInformation(newDeviceSettings.AdapterOrdinal); UpdateDeviceStats(newDeviceSettings.DeviceType, newDeviceSettings.BehaviorFlags, adapterInfo.AdapterInformation); } // Get the adapter monitor State.AdapterMonitor = Manager.GetAdapterMonitor((int)newDeviceSettings.AdapterOrdinal); // When moving from full screen to windowed mode, it is important to // adjust the window size after resetting the device rather than // beforehand to ensure that you get the window size you want. For // example, when switching from 640x480 full screen to windowed with // a 1000x600 window on a 1024x768 desktop, it is impossible to set // the window size to 1000x600 until after the display mode has // changed to 1024x768, because windows cannot be larger than the // desktop. if (newDeviceSettings.presentParams.Windowed) { if (State.WindowFocus == null) { System.Drawing.Rectangle rect = State.WindowBoundsRectangle; // Resize the window System.Drawing.Point pt = rect.Location; pt = Window.PointToScreen(pt); if (!State.IsMaximized) { Window.SetBounds(pt.X, pt.Y, rect.Width, rect.Height, System.Windows.Forms.BoundsSpecified.All); } // Check to see if the monitor has changed windows NativeMethods.MonitorInformation infoAdapter = new NativeMethods.MonitorInformation(); // Set size infoAdapter.Size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(NativeMethods.MonitorInformation)); NativeMethods.GetMonitorInfo(State.AdapterMonitor, ref infoAdapter); // Calculate width/height, this needs to happen because the unmanaged RECT structure is different than the managed Rectangle int monitorWidth = infoAdapter.WorkRectangle.Right - infoAdapter.WorkRectangle.Left; int monitorHeight = infoAdapter.WorkRectangle.Bottom - infoAdapter.WorkRectangle.Top; // Get the monitor this app is on IntPtr monitorHandle = NativeMethods.MonitorFromWindow(Window.Handle, 1); // Default to primary NativeMethods.MonitorInformation infoWindow = new NativeMethods.MonitorInformation(); // Set size infoWindow.Size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(NativeMethods.MonitorInformation)); NativeMethods.GetMonitorInfo(monitorHandle, ref infoWindow); rect = State.WindowBoundsRectangle; int windowOffsetX = rect.Left - infoWindow.MonitorRectangle.Left; int windowOffsetY = rect.Top - infoWindow.MonitorRectangle.Top; int windowWidth = rect.Right - rect.Left; int windowHeight = rect.Bottom - rect.Top; if (State.IsWindowCreatedWithDefaultPositions) { // Since the window was created with a default window position // center it in the work area if its outside the monitor's work area // Only do this the first time. State.IsWindowCreatedWithDefaultPositions = false; // Center window if the bottom or right of the window is outside the monitor's work area if (infoAdapter.WorkRectangle.Left + windowOffsetX + windowWidth > infoAdapter.WorkRectangle.Right) windowOffsetX = (monitorWidth - windowWidth) / 2; if (infoAdapter.WorkRectangle.Top + windowOffsetY + windowHeight > infoAdapter.WorkRectangle.Bottom) windowOffsetY = (monitorHeight - windowHeight) / 2; } // Move & show the window pt.X = infoAdapter.MonitorRectangle.Left + windowOffsetX; pt.Y = infoAdapter.MonitorRectangle.Top + windowOffsetY; } } else { // Just store the full screen client rectangle State.FullScreenClientRectangle = new System.Drawing.Rectangle(0,0, newDeviceSettings.presentParams.BackBufferWidth, newDeviceSettings.presentParams.BackBufferHeight); } // Done creating the device State.AreSizeChangesIgnored = false; Pause(false, false); State.WasDeviceCreated = true; }
/// <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 a specific device combination from a device settings object /// </summary> public static EnumDeviceSettingsCombo GetDeviceSettingsCombo(DeviceSettings settings) { return GetDeviceSettingsCombo(settings.AdapterOrdinal, settings.DeviceType, settings.AdapterFormat, settings.presentParams.BackBufferFormat, settings.presentParams.Windowed); }
/// <summary> /// Calls FindValidDeviceSettings with default match options (all ignore) /// </summary> private DeviceSettings FindValidDeviceSettings(DeviceSettings settings) { return FindValidDeviceSettings(settings, new MatchOptions()); }
/// <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>Changes the UI defaults to the current device settings</summary> public void Refresh() { // Get some information globalSettings = parent.DeviceSettings.Clone(); System.Drawing.Rectangle client = parent.WindowClientRectangle; windowWidth = (uint)client.Width; windowHeight = (uint)client.Height; // Fill the UI with the current settings if (!deviceCombo.ContainsItem(globalSettings.DeviceType.ToString())) deviceCombo.AddItem(globalSettings.DeviceType.ToString(), globalSettings.DeviceType.ToString()); SetWindowed(globalSettings.presentParams.Windowed); clipBox.IsChecked = ((globalSettings.presentParams.PresentFlag & PresentFlag.DeviceClip) != 0); if (!adapterFormatCombo.ContainsItem(globalSettings.AdapterFormat.ToString())) adapterFormatCombo.AddItem(globalSettings.AdapterFormat.ToString(), globalSettings.AdapterFormat); AddResolution((short)globalSettings.presentParams.BackBufferWidth, (short)globalSettings.presentParams.BackBufferHeight); AddRefreshRate(globalSettings.presentParams.FullScreenRefreshRateInHz); if (!backBufferCombo.ContainsItem(globalSettings.presentParams.BackBufferFormat.ToString())) backBufferCombo.AddItem(globalSettings.presentParams.BackBufferFormat.ToString(), globalSettings.presentParams.BackBufferFormat); if (!depthStencilCombo.ContainsItem(globalSettings.presentParams.AutoDepthStencilFormat.ToString())) depthStencilCombo.AddItem(globalSettings.presentParams.AutoDepthStencilFormat.ToString(), globalSettings.presentParams.AutoDepthStencilFormat); if (!multiSampleTypeCombo.ContainsItem(globalSettings.presentParams.MultiSample.ToString())) multiSampleTypeCombo.AddItem(globalSettings.presentParams.MultiSample.ToString(), globalSettings.presentParams.MultiSample); if (!multiSampleQualityCombo.ContainsItem(globalSettings.presentParams.MultiSampleQuality.ToString())) multiSampleQualityCombo.AddItem(globalSettings.presentParams.MultiSampleQuality.ToString(), globalSettings.presentParams.MultiSampleQuality); if (!presentCombo.ContainsItem(globalSettings.presentParams.PresentationInterval.ToString())) presentCombo.AddItem(globalSettings.presentParams.PresentationInterval.ToString(), globalSettings.presentParams.PresentationInterval); BehaviorFlags flags = new BehaviorFlags(globalSettings.BehaviorFlags); if (flags.PureDevice) AddVertexProcessing(CreateFlags.PureDevice); else if (flags.HardwareVertexProcessing) AddVertexProcessing(CreateFlags.HardwareVertexProcessing); else if (flags.SoftwareVertexProcessing) AddVertexProcessing(CreateFlags.SoftwareVertexProcessing); else if (flags.MixedVertexProcessing) AddVertexProcessing(CreateFlags.MixedVertexProcessing); // Get the adapters list from Enumeration object ArrayList adapterInfoList = Enumeration.AdapterInformationList; if (adapterInfoList.Count == 0) throw new NoCompatibleDevicesException(); adapterCombo.Clear(); // Add all of the adapters for (int iAdapter = 0; iAdapter < adapterInfoList.Count; iAdapter++) { EnumAdapterInformation adapterInfo = adapterInfoList[iAdapter] as EnumAdapterInformation; if (!adapterCombo.ContainsItem(adapterInfo.UniqueDescription)) adapterCombo.AddItem(adapterInfo.UniqueDescription, iAdapter); } adapterCombo.SetSelectedByData(globalSettings.AdapterOrdinal); // The adapter changed, call the handler OnAdapterChanged(adapterCombo, EventArgs.Empty); Dialog.SetRefreshTime((float)FrameworkTimer.GetTime()); }
/// <summary>Changes the UI defaults to the current device settings</summary> public void Refresh() { // Get some information globalSettings = parent.DeviceSettings.Clone(); System.Drawing.Rectangle client = parent.WindowClientRectangle; windowWidth = (uint)client.Width; windowHeight = (uint)client.Height; // Fill the UI with the current settings if (!deviceCombo.ContainsItem(globalSettings.DeviceType.ToString())) { deviceCombo.AddItem(globalSettings.DeviceType.ToString(), globalSettings.DeviceType.ToString()); } SetWindowed(globalSettings.presentParams.Windowed); clipBox.IsChecked = ((globalSettings.presentParams.PresentFlag & PresentFlag.DeviceClip) != 0); if (!adapterFormatCombo.ContainsItem(globalSettings.AdapterFormat.ToString())) { adapterFormatCombo.AddItem(globalSettings.AdapterFormat.ToString(), globalSettings.AdapterFormat); } AddResolution((short)globalSettings.presentParams.BackBufferWidth, (short)globalSettings.presentParams.BackBufferHeight); AddRefreshRate(globalSettings.presentParams.FullScreenRefreshRateInHz); if (!backBufferCombo.ContainsItem(globalSettings.presentParams.BackBufferFormat.ToString())) { backBufferCombo.AddItem(globalSettings.presentParams.BackBufferFormat.ToString(), globalSettings.presentParams.BackBufferFormat); } if (!depthStencilCombo.ContainsItem(globalSettings.presentParams.AutoDepthStencilFormat.ToString())) { depthStencilCombo.AddItem(globalSettings.presentParams.AutoDepthStencilFormat.ToString(), globalSettings.presentParams.AutoDepthStencilFormat); } if (!multiSampleTypeCombo.ContainsItem(globalSettings.presentParams.MultiSample.ToString())) { multiSampleTypeCombo.AddItem(globalSettings.presentParams.MultiSample.ToString(), globalSettings.presentParams.MultiSample); } if (!multiSampleQualityCombo.ContainsItem(globalSettings.presentParams.MultiSampleQuality.ToString())) { multiSampleQualityCombo.AddItem(globalSettings.presentParams.MultiSampleQuality.ToString(), globalSettings.presentParams.MultiSampleQuality); } if (!presentCombo.ContainsItem(globalSettings.presentParams.PresentationInterval.ToString())) { presentCombo.AddItem(globalSettings.presentParams.PresentationInterval.ToString(), globalSettings.presentParams.PresentationInterval); } BehaviorFlags flags = new BehaviorFlags(globalSettings.BehaviorFlags); if (flags.PureDevice) { AddVertexProcessing(CreateFlags.PureDevice); } else if (flags.HardwareVertexProcessing) { AddVertexProcessing(CreateFlags.HardwareVertexProcessing); } else if (flags.SoftwareVertexProcessing) { AddVertexProcessing(CreateFlags.SoftwareVertexProcessing); } else if (flags.MixedVertexProcessing) { AddVertexProcessing(CreateFlags.MixedVertexProcessing); } // Get the adapters list from Enumeration object ArrayList adapterInfoList = Enumeration.AdapterInformationList; if (adapterInfoList.Count == 0) { throw new NoCompatibleDevicesException(); } adapterCombo.Clear(); // Add all of the adapters for (int iAdapter = 0; iAdapter < adapterInfoList.Count; iAdapter++) { EnumAdapterInformation adapterInfo = adapterInfoList[iAdapter] as EnumAdapterInformation; if (!adapterCombo.ContainsItem(adapterInfo.UniqueDescription)) { adapterCombo.AddItem(adapterInfo.UniqueDescription, iAdapter); } } adapterCombo.SetSelectedByData(globalSettings.AdapterOrdinal); // The adapter changed, call the handler OnAdapterChanged(adapterCombo, EventArgs.Empty); Dialog.SetRefreshTime((float)FrameworkTimer.GetTime()); }
/// <summary> /// This callback function is called immediately before a device is created to allow the /// application to modify the device settings. The supplied settings parameter /// contains the settings that the framework has selected for the new device, and the /// application can make any desired changes directly to this structure. Note however that /// the sample framework will not correct invalid device settings so care must be taken /// to return valid device settings, otherwise creating the Device will fail. /// </summary> public void ModifyDeviceSettings(DeviceSettings settings, Caps caps) { // If device doesn't support 2.0 pixel shaders, switch to reference device if(caps.PixelShaderVersion < new Version(2, 0)) { settings.DeviceType=DeviceType.Reference; settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing; MessageBox.Show("Your graphics card does not support the required pixel shader version.\n"+ "Switching to reference mod (expect a maximum fps of ~1)","Warning"); if(AA!=0 && AA!= 4 && AA!=9) { MessageBox.Show("Your chosen antialiasing setting is unsupported by the reference rasterizer.\n"+ "Defaulting to off", "Warning"); AA=0; } if(AF!=0 && AF!=2 && AF!=4 && AF!=8 && AF!=16) { MessageBox.Show("Your chosen anisotropic filtering setting is unsupported by the reference rasterizer.\n"+ "Defaulting to linear filters","Warning"); AF=0; } } else { // If device doesn't support HW T&L or doesn't support 2.0 vertex shaders in HW then switch to SWVP. if((!caps.DeviceCaps.SupportsHardwareTransformAndLight) || (caps.VertexShaderVersion < new Version(2, 0))) { settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing; } else { settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing; } // This application is designed to work on a pure device by not using // any get methods, so create a pure device if supported and using HWVP. if((caps.DeviceCaps.SupportsPureDevice) && ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0)) settings.BehaviorFlags |= CreateFlags.PureDevice; settings.BehaviorFlags |= CreateFlags.MultiThreaded; //Because .NET has a habit of randomly swapping threads if(AF!=0) { if((AF!=2 && AF!=4 && AF!=8 && AF!=16) || AF>caps.MaxAnisotropy) { MessageBox.Show("Your chosen anisotropic filtering setting is unsupported by your graphics hardware.\n"+ "Defaulting to linear filters","Warning"); AF=0; } } } settings.presentParams.MultiSample=(MultiSampleType)AA; }
/// <summary> /// Passes a previously created Direct3D device for use by the framework. /// If CreateWindow() has not already been called, it will call it with the /// default parameters. Instead of calling this, you can call CreateDevice() or /// CreateDeviceFromSettings() /// </summary> public void SetDevice(Device device) { if (device == null) throw new ArgumentNullException("device", "You cannot pass in a null device to SetDevice"); if (State.IsInsideDeviceCallback) throw new InvalidOperationException("You cannot set a device from inside a callback."); // Was the window created? If not, create it now if (!State.WasWindowCreated) { // If CreateWindow or SetWindow was already called and failed, then fail again. if (State.WasWindowCreateCalled) { throw new InvalidOperationException("CreateWindow was already called and failed."); } // Create a default window CreateWindow("Direct3D Window", null, null, -1, -1); } DeviceSettings deviceSettings = new DeviceSettings(); // Get the present parameters from the swap chain using(Surface backBuffer = device.GetBackBuffer(0, 0, BackBufferType.Mono)) { using (SwapChain swap = backBuffer.GetContainer(InterfaceGuid.SwapChain) as SwapChain) { deviceSettings.presentParams = swap.PresentParameters; System.Diagnostics.Debug.Assert(deviceSettings.presentParams != null, "You must have valid present parameters here."); } } DeviceCreationParameters creationParams = device.CreationParameters; // Fill out the device settings structure now deviceSettings.AdapterOrdinal = (uint)creationParams.AdapterOrdinal; deviceSettings.DeviceType = creationParams.DeviceType; deviceSettings.AdapterFormat = FindAdapterFormat(deviceSettings.AdapterOrdinal, deviceSettings.DeviceType, deviceSettings.presentParams.BackBufferFormat, deviceSettings.presentParams.Windowed); deviceSettings.BehaviorFlags = creationParams.Behavior.Value; // Change to the Direct3D device passed in ChangeDevice(deviceSettings, device, false); }
/// <summary> /// Creates a Direct3D device. If CreateWindow or SetWindow has not already /// been called, it will call CreateWindow with default parameters. /// Instead of calling this, you can call SetDevice or CreateDeviceFromSettings /// </summary> public void CreateDevice(uint adapterOridinal, bool windowed, int suggestedWidth, int suggestedHeight, IDeviceCreation callback) { if (State.IsInsideDeviceCallback) throw new InvalidOperationException("You cannot create a window from inside a callback."); // Store callbacks in global state SetDeviceCreationInterface(callback); // Update device create being called State.WasDeviceCreateCalled = true; // Was the window created? If not, create it now if (!State.WasWindowCreated) { // If CreateWindow or SetWindow was already called and failed, then fail again. if (State.WasWindowCreateCalled) { throw new InvalidOperationException("CreateWindow was already called and failed."); } // Create a default window CreateWindow("Direct3D Window", null, null, -1, -1); } // Force an enumeration with the updated Device Acceptable callback Enumeration.Enumerate(State.DeviceCreationInterface); // Set up the match options MatchOptions match = new MatchOptions(); match.AdapterOrdinal = MatchType.PreserveInput; match.DeviceType = MatchType.IgnoreInput; match.Windowed = MatchType.PreserveInput; match.AdapterFormat = MatchType.IgnoreInput; match.VertexProcessing = MatchType.IgnoreInput; match.Resolution = MatchType.ClosestToInput; match.BackBufferFormat = MatchType.IgnoreInput; match.BackBufferCount = MatchType.IgnoreInput; match.MultiSample = MatchType.IgnoreInput; match.SwapEffect = MatchType.IgnoreInput; match.DepthFormat = MatchType.IgnoreInput; match.StencilFormat = MatchType.IgnoreInput; match.PresentFlags = MatchType.IgnoreInput; match.RefreshRate = MatchType.IgnoreInput; match.PresentInterval = MatchType.IgnoreInput; // Get the device settings DeviceSettings settings = new DeviceSettings(); settings.presentParams = new PresentParameters(); settings.AdapterOrdinal = adapterOridinal; settings.presentParams.Windowed = windowed; settings.presentParams.BackBufferWidth = suggestedWidth; settings.presentParams.BackBufferHeight = suggestedHeight; // Override with settings for command line if (State.OverrideWidth != 0) settings.presentParams.BackBufferWidth = State.OverrideWidth; if (State.OverrideHeight != 0) settings.presentParams.BackBufferHeight = State.OverrideHeight; if (State.OverrideAdapterOrdinal != -1) settings.AdapterOrdinal = (uint)State.OverrideAdapterOrdinal; if (State.IsOverridingFullScreen) { settings.presentParams.Windowed = false; if ((State.OverrideWidth == 0) && (State.OverrideHeight == 0)) match.Resolution = MatchType.IgnoreInput; } if (State.IsOverridingWindowed) settings.presentParams.Windowed = true; if (State.IsOverridingForceHardware) { settings.DeviceType = DeviceType.Hardware; match.DeviceType = MatchType.PreserveInput; } if (State.IsOverridingForceReference) { settings.DeviceType = DeviceType.Reference; match.DeviceType = MatchType.PreserveInput; } if (State.IsOverridingForcePureHardwareVertexProcessing) { settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing | CreateFlags.PureDevice; match.VertexProcessing = MatchType.PreserveInput; } if (State.IsOverridingForceHardwareVertexProcessing) { settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing; match.VertexProcessing = MatchType.PreserveInput; } if (State.IsOverridingForceSoftwareVertexProcessing) { settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing; match.VertexProcessing = MatchType.PreserveInput; } try { settings = FindValidDeviceSettings(settings, match); } catch(Exception e) { DisplayErrorMessage(e); throw; } // If the modify device callback isn't null, call it to // let the app change the settings if (State.DeviceCreationInterface != null) { Caps c = Manager.GetDeviceCaps((int)settings.AdapterOrdinal, settings.DeviceType); State.DeviceCreationInterface.ModifyDeviceSettings(settings, c); } // Change to a Direct3D device created from the new device settings // If there is an existing device, either reset or recreate ChangeDevice(settings, null, false); }
/// <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> /// 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> /// public helper function to build a 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. /// </summary> private DeviceSettings BuildOptimalDeviceSettings(DeviceSettings settings, MatchOptions match) { DeviceSettings optimal = new DeviceSettings(); // This will be what we return optimal.presentParams = new PresentParameters(); //--------------------- // Adapter ordinal //--------------------- if (match.AdapterOrdinal == MatchType.IgnoreInput) optimal.AdapterOrdinal = 0; else optimal.AdapterOrdinal = settings.AdapterOrdinal; //--------------------- // Device type //--------------------- if (match.DeviceType == MatchType.IgnoreInput) optimal.DeviceType = DeviceType.Hardware; else optimal.DeviceType = settings.DeviceType; //--------------------- // Windowed //--------------------- if (match.Windowed == MatchType.IgnoreInput) optimal.presentParams.Windowed = true; else optimal.presentParams.Windowed = settings.presentParams.Windowed; //--------------------- // Adapter format //--------------------- if (match.AdapterFormat == MatchType.IgnoreInput) { // If windowed, default to the desktop display mode // If fullscreen, default to the desktop display mode for quick mode change or // default to Format.X8R8G8B8 if the desktop display mode is < 32bit DisplayMode adapterDesktopMode = Manager.Adapters[(int)optimal.AdapterOrdinal].CurrentDisplayMode; if (optimal.presentParams.Windowed || ManagedUtility.GetColorChannelBits(adapterDesktopMode.Format) >= 8 ) optimal.AdapterFormat = adapterDesktopMode.Format; else optimal.AdapterFormat = Format.X8R8G8B8; } else { optimal.AdapterFormat = settings.AdapterFormat; } //--------------------- // Vertex processing //--------------------- if (match.VertexProcessing == MatchType.IgnoreInput) optimal.BehaviorFlags = CreateFlags.HardwareVertexProcessing; else optimal.BehaviorFlags = settings.BehaviorFlags; //--------------------- // Resolution //--------------------- if (match.Resolution == MatchType.IgnoreInput) { // If windowed, default to 640x480 // If fullscreen, default to the desktop res for quick mode change if (optimal.presentParams.Windowed ) { optimal.presentParams.BackBufferWidth = DefaultSizeWidth; optimal.presentParams.BackBufferHeight = DefaultSizeHeight; } else { DisplayMode adapterDesktopMode = Manager.Adapters[(int)optimal.AdapterOrdinal].CurrentDisplayMode; optimal.presentParams.BackBufferWidth = adapterDesktopMode.Width; optimal.presentParams.BackBufferHeight = adapterDesktopMode.Height; } } else { optimal.presentParams.BackBufferWidth = settings.presentParams.BackBufferWidth; optimal.presentParams.BackBufferHeight = settings.presentParams.BackBufferHeight; } //--------------------- // Back buffer format //--------------------- if (match.BackBufferFormat == MatchType.IgnoreInput) optimal.presentParams.BackBufferFormat = optimal.AdapterFormat; // Default to match the adapter format else optimal.presentParams.BackBufferFormat = settings.presentParams.BackBufferFormat; //--------------------- // Back buffer count //--------------------- if (match.BackBufferCount == MatchType.IgnoreInput) optimal.presentParams.BackBufferCount = 2; // Default to triple buffering for perf gain else optimal.presentParams.BackBufferCount = settings.presentParams.BackBufferCount; //--------------------- // Multisample //--------------------- if (match.MultiSample == MatchType.IgnoreInput) optimal.presentParams.MultiSampleQuality = 0; // Default to no multisampling else optimal.presentParams.MultiSampleQuality = settings.presentParams.MultiSampleQuality; //--------------------- // Swap effect //--------------------- if (match.SwapEffect == MatchType.IgnoreInput) optimal.presentParams.SwapEffect = SwapEffect.Discard; else optimal.presentParams.SwapEffect = settings.presentParams.SwapEffect; //--------------------- // Depth stencil //--------------------- if (match.DepthFormat == MatchType.IgnoreInput && match.StencilFormat == MatchType.IgnoreInput) { uint backBufferBits = ManagedUtility.GetColorChannelBits(optimal.presentParams.BackBufferFormat); if (backBufferBits >= 8) optimal.presentParams.AutoDepthStencilFormat = DepthFormat.D32; else optimal.presentParams.AutoDepthStencilFormat = DepthFormat.D16; } else { optimal.presentParams.AutoDepthStencilFormat = settings.presentParams.AutoDepthStencilFormat; } //--------------------- // Present flags //--------------------- if (match.PresentFlags == MatchType.IgnoreInput) optimal.presentParams.PresentFlag = PresentFlag.DiscardDepthStencil; else optimal.presentParams.PresentFlag = settings.presentParams.PresentFlag; //--------------------- // Refresh rate //--------------------- if (match.RefreshRate == MatchType.IgnoreInput) optimal.presentParams.FullScreenRefreshRateInHz = 0; else optimal.presentParams.FullScreenRefreshRateInHz = settings.presentParams.FullScreenRefreshRateInHz; //--------------------- // Present interval //--------------------- if (match.PresentInterval == MatchType.IgnoreInput) { // For windowed, default to PresentInterval.Immediate // which will wait not for the vertical retrace period to prevent tearing, // but may introduce tearing. // For full screen, default to PresentInterval.Default // which will wait for the vertical retrace period to prevent tearing. if (optimal.presentParams.Windowed ) optimal.presentParams.PresentationInterval = PresentInterval.Immediate; else optimal.presentParams.PresentationInterval = PresentInterval.Default; } else { optimal.presentParams.PresentationInterval = settings.presentParams.PresentationInterval; } return optimal; }
/// <summary> /// Returns a specific device combination from a device settings object /// </summary> public static EnumDeviceSettingsCombo GetDeviceSettingsCombo(DeviceSettings settings) { return(GetDeviceSettingsCombo(settings.AdapterOrdinal, settings.DeviceType, settings.AdapterFormat, settings.presentParams.BackBufferFormat, settings.presentParams.Windowed)); }