www.pudn.com > IntroductionTo3DGameEngineDesign.rar > D3DEnumeration.cs
//----------------------------------------------------------------------------- // File: D3DEnumeration.cs // // Desc: Enumerates D3D adapters, devices, modes, etc. // // Copyright (c) 2001-2002 Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using System; using System.Collections; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; ////// Enumeration of all possible D3D vertex processing types /// public enum VertexProcessingType { Software, Mixed, Hardware, PureHardware } ////// Info about a display adapter /// public class GraphicsAdapterInfo { public int AdapterOrdinal; public AdapterDetails AdapterDetails; public ArrayList DisplayModeList = new ArrayList(); // List of D3DDISPLAYMODEs public ArrayList DeviceInfoList = new ArrayList(); // List of D3DDeviceInfos public override string ToString() { return AdapterDetails.Description; } } ////// Info about a D3D device, including a list of DeviceCombos (see below) /// that work with the device /// public class GraphicsDeviceInfo { public int AdapterOrdinal; public DeviceType DevType; public Caps Caps; public ArrayList DeviceComboList = new ArrayList(); // List of D3DDeviceCombos public override string ToString() { return DevType.ToString(); } } ////// Info about a depth/stencil buffer format that is incompatible with a /// multisample type /// public class DepthStencilMultiSampleConflict { public DepthFormat DepthStencilFormat; public MultiSampleType MultiSampleType; } ////// A combination of adapter format, back buffer format, and windowed/fullscreen /// that is compatible with a particular D3D device (and the app) /// public class DeviceCombo { public int AdapterOrdinal; public DeviceType DevType; public Format AdapterFormat; public Format BackBufferFormat; public bool IsWindowed; public ArrayList DepthStencilFormatList = new ArrayList(); // List of D3DFORMATs public ArrayList MultiSampleTypeList = new ArrayList(); // List of D3DMULTISAMPLE_TYPEs public ArrayList MultiSampleQualityList = new ArrayList(); // List of ints (maxQuality per multisample type) public ArrayList DepthStencilMultiSampleConflictList = new ArrayList(); // List of DepthStencilMultiSampleConflicts public ArrayList VertexProcessingTypeList = new ArrayList(); // List of VertexProcessingTypes public ArrayList PresentIntervalList = new ArrayList(); // List of D3DPRESENT_INTERVALs } ////// Used to sort Displaymodes /// class DisplayModeComparer : System.Collections.IComparer { ////// Compare two display modes /// public int Compare(object x, object y) { DisplayMode dx = (DisplayMode)x; DisplayMode dy = (DisplayMode)y; if (dx.Width > dy.Width) return 1; if (dx.Width < dy.Width) return -1; if (dx.Height > dy.Height) return 1; if (dx.Height < dy.Height) return -1; if (dx.Format > dy.Format) return 1; if (dx.Format < dy.Format) return -1; if (dx.RefreshRate > dy.RefreshRate) return 1; if (dx.RefreshRate < dy.RefreshRate) return -1; return 0; } } ////// Enumerates available adapters, devices, modes, etc. /// public class D3DEnumeration { ////// The confirm device delegate which is used to determine if a device /// meets the needs of the simulation /// public delegate bool ConfirmDeviceCallbackType(Caps caps, VertexProcessingType vertexProcessingType, Format backBufferFormat); public ConfirmDeviceCallbackType ConfirmDeviceCallback; public ArrayList AdapterInfoList = new ArrayList(); // List of D3DAdapterInfos // The following variables can be used to limit what modes, formats, // etc. are enumerated. Set them to the values you want before calling // Enumerate(). public int AppMinFullscreenWidth = 640; public int AppMinFullscreenHeight = 480; public int AppMinColorChannelBits = 5; // min color bits per channel in adapter format public int AppMinAlphaChannelBits = 0; // min alpha bits per pixel in back buffer format public int AppMinDepthBits = 15; public int AppMinStencilBits = 0; public bool AppUsesDepthBuffer = true; public bool AppUsesMixedVP = false; // whether app can take advantage of mixed vp mode public bool AppRequiresWindowed = false; public bool AppRequiresFullscreen = false; ////// Enumerates available D3D adapters, devices, modes, etc. /// public void Enumerate() { foreach (AdapterInformation ai in Manager.Adapters) { ArrayList adapterFormatList = new ArrayList(); GraphicsAdapterInfo adapterInfo = new GraphicsAdapterInfo(); adapterInfo.AdapterOrdinal = ai.Adapter; adapterInfo.AdapterDetails = ai.Information; // Get list of all display modes on this adapter. // Also build a temporary list of all display adapter formats. foreach (DisplayMode displayMode in ai.SupportedDisplayModes) { if (displayMode.Width < AppMinFullscreenWidth) continue; if (displayMode.Height < AppMinFullscreenHeight) continue; if (GraphicsUtility.GetColorChannelBits(displayMode.Format) < AppMinColorChannelBits) continue; adapterInfo.DisplayModeList.Add(displayMode); if (!adapterFormatList.Contains(displayMode.Format)) adapterFormatList.Add(displayMode.Format); } // Sort displaymode list DisplayModeComparer dmc = new DisplayModeComparer(); adapterInfo.DisplayModeList.Sort(dmc); // Get info for each device on this adapter EnumerateDevices(adapterInfo, adapterFormatList); // If at least one device on this adapter is available and compatible // with the app, add the adapterInfo to the list if (adapterInfo.DeviceInfoList.Count == 0) continue; AdapterInfoList.Add(adapterInfo); } } ////// Enumerates D3D devices for a particular adapter /// protected void EnumerateDevices(GraphicsAdapterInfo adapterInfo, ArrayList adapterFormatList) { DeviceType[] devTypeArray = new DeviceType[] { DeviceType.Hardware, DeviceType.Software, DeviceType.Reference }; foreach( DeviceType devType in devTypeArray) { GraphicsDeviceInfo deviceInfo = new GraphicsDeviceInfo(); deviceInfo.AdapterOrdinal = adapterInfo.AdapterOrdinal; deviceInfo.DevType = devType; try { deviceInfo.Caps = Manager.GetDeviceCaps(adapterInfo.AdapterOrdinal, devType); } catch (DirectXException) { continue; } // Get info for each devicecombo on this device EnumerateDeviceCombos(deviceInfo, adapterFormatList); // If at least one devicecombo for this device is found, // add the deviceInfo to the list if (deviceInfo.DeviceComboList.Count == 0) continue; adapterInfo.DeviceInfoList.Add(deviceInfo); } } ////// Enumerates DeviceCombos for a particular device /// protected void EnumerateDeviceCombos(GraphicsDeviceInfo deviceInfo, ArrayList adapterFormatList) { Format[] backBufferFormatArray = new Format[] { Format.R8G8B8, Format.A8R8G8B8, Format.X8R8G8B8, Format.R5G6B5, Format.A1R5G5B5, Format.X1R5G5B5, Format.R3G3B2, Format.A8R3G3B2, Format.X4R4G4B4, Format.A4R4G4B4, Format.A2B10G10R10 }; bool[] isWindowedArray = new bool[] { false, true }; // See which adapter formats are supported by this device foreach (Format adapterFormat in adapterFormatList) { foreach (Format backBufferFormat in backBufferFormatArray) { if (GraphicsUtility.GetAlphaChannelBits(backBufferFormat) < AppMinAlphaChannelBits) continue; foreach (bool isWindowed in isWindowedArray) { if (!isWindowed && AppRequiresWindowed) continue; if (isWindowed && AppRequiresFullscreen) continue; if (!Manager.CheckDeviceType(deviceInfo.AdapterOrdinal, deviceInfo.DevType, adapterFormat, backBufferFormat, isWindowed) ) { continue; } // At this point, we have an adapter/device/adapterformat/backbufferformat/iswindowed // DeviceCombo that is supported by the system. We still need to confirm that it's // compatible with the app, and find one or more suitable depth/stencil buffer format, // multisample type, vertex processing type, and present interval. DeviceCombo deviceCombo = new DeviceCombo(); deviceCombo.AdapterOrdinal = deviceInfo.AdapterOrdinal; deviceCombo.DevType = deviceInfo.DevType; deviceCombo.AdapterFormat = adapterFormat; deviceCombo.BackBufferFormat = backBufferFormat; deviceCombo.IsWindowed = isWindowed; if (AppUsesDepthBuffer) { BuildDepthStencilFormatList(deviceCombo); if (deviceCombo.DepthStencilFormatList.Count == 0) continue; } BuildMultiSampleTypeList(deviceCombo); if (deviceCombo.MultiSampleTypeList.Count == 0) continue; BuildDepthStencilMultiSampleConflictList(deviceCombo); BuildVertexProcessingTypeList(deviceInfo, deviceCombo); if (deviceCombo.VertexProcessingTypeList.Count == 0) continue; BuildPresentIntervalList(deviceInfo, deviceCombo); if (deviceCombo.PresentIntervalList.Count == 0) continue; deviceInfo.DeviceComboList.Add(deviceCombo); } } } } ////// Adds all depth/stencil formats that are compatible with the device and app to /// the given deviceCombo /// public void BuildDepthStencilFormatList(DeviceCombo deviceCombo) { DepthFormat[] depthStencilFormatArray = { DepthFormat.D16, DepthFormat.D15S1, DepthFormat.D24X8, DepthFormat.D24S8, DepthFormat.D24X4S4, DepthFormat.D32, }; foreach (DepthFormat depthStencilFmt in depthStencilFormatArray) { if (GraphicsUtility.GetDepthBits(depthStencilFmt) < AppMinDepthBits) continue; if (GraphicsUtility.GetStencilBits(depthStencilFmt) < AppMinStencilBits) continue; if (Manager.CheckDeviceFormat(deviceCombo.AdapterOrdinal, deviceCombo.DevType, deviceCombo.AdapterFormat, Usage.DepthStencil, ResourceType.Surface, depthStencilFmt)) { if (Manager.CheckDepthStencilMatch(deviceCombo.AdapterOrdinal, deviceCombo.DevType, deviceCombo.AdapterFormat, deviceCombo.BackBufferFormat, depthStencilFmt)) { deviceCombo.DepthStencilFormatList.Add(depthStencilFmt); } } } } ////// Adds all multisample types that are compatible with the device and app to /// the given deviceCombo /// public void BuildMultiSampleTypeList(DeviceCombo deviceCombo) { MultiSampleType[] msTypeArray = { MultiSampleType.None, MultiSampleType.NonMaskable, MultiSampleType.TwoSamples, MultiSampleType.ThreeSamples, MultiSampleType.FourSamples, MultiSampleType.FiveSamples, MultiSampleType.SixSamples, MultiSampleType.SevenSamples, MultiSampleType.EightSamples, MultiSampleType.NineSamples, MultiSampleType.TenSamples, MultiSampleType.ElevenSamples, MultiSampleType.TwelveSamples, MultiSampleType.ThirteenSamples, MultiSampleType.FourteenSamples, MultiSampleType.FifteenSamples, MultiSampleType.SixteenSamples, }; foreach (MultiSampleType msType in msTypeArray) { int result; int qualityLevels = 0; if (Manager.CheckDeviceMultiSampleType(deviceCombo.AdapterOrdinal, deviceCombo.DevType, deviceCombo.BackBufferFormat, deviceCombo.IsWindowed, msType, out result, ref qualityLevels)) { deviceCombo.MultiSampleTypeList.Add(msType); deviceCombo.MultiSampleQualityList.Add(qualityLevels); } } } ////// Finds any depthstencil formats that are incompatible with multisample types and /// builds a list of them. /// public void BuildDepthStencilMultiSampleConflictList(DeviceCombo deviceCombo) { DepthStencilMultiSampleConflict DSMSConflict; foreach (DepthFormat dsFmt in deviceCombo.DepthStencilFormatList) { foreach (MultiSampleType msType in deviceCombo.MultiSampleTypeList) { if (!Manager.CheckDeviceMultiSampleType(deviceCombo.AdapterOrdinal, deviceCombo.DevType, (Format)dsFmt, deviceCombo.IsWindowed, msType)) { DSMSConflict = new DepthStencilMultiSampleConflict(); DSMSConflict.DepthStencilFormat = dsFmt; DSMSConflict.MultiSampleType = msType; deviceCombo.DepthStencilMultiSampleConflictList.Add(DSMSConflict); } } } } ////// Adds all vertex processing types that are compatible with the device and app to /// the given deviceCombo /// public void BuildVertexProcessingTypeList(GraphicsDeviceInfo deviceInfo, DeviceCombo deviceCombo) { if (deviceInfo.Caps.DeviceCaps.SupportsHardwareTransformAndLight ) { if (deviceInfo.Caps.DeviceCaps.SupportsPureDevice ) { if (ConfirmDeviceCallback == null || ConfirmDeviceCallback(deviceInfo.Caps, VertexProcessingType.PureHardware, deviceCombo.BackBufferFormat)) { deviceCombo.VertexProcessingTypeList.Add(VertexProcessingType.PureHardware); } } if (ConfirmDeviceCallback == null || ConfirmDeviceCallback(deviceInfo.Caps, VertexProcessingType.Hardware, deviceCombo.BackBufferFormat)) { deviceCombo.VertexProcessingTypeList.Add(VertexProcessingType.Hardware); } if (AppUsesMixedVP && (ConfirmDeviceCallback == null || ConfirmDeviceCallback(deviceInfo.Caps, VertexProcessingType.Mixed, deviceCombo.BackBufferFormat))) { deviceCombo.VertexProcessingTypeList.Add(VertexProcessingType.Mixed); } } if (ConfirmDeviceCallback == null || ConfirmDeviceCallback(deviceInfo.Caps, VertexProcessingType.Software, deviceCombo.BackBufferFormat)) { deviceCombo.VertexProcessingTypeList.Add(VertexProcessingType.Software); } } ////// Adds all present intervals that are compatible with the device and app to /// the given deviceCombo /// public void BuildPresentIntervalList(GraphicsDeviceInfo deviceInfo, DeviceCombo deviceCombo) { PresentInterval[] piArray = { PresentInterval.Immediate, PresentInterval.Default, PresentInterval.One, PresentInterval.Two, PresentInterval.Three, PresentInterval.Four, }; foreach (PresentInterval pi in piArray) { if( deviceCombo.IsWindowed ) { if( pi == PresentInterval.Two || pi == PresentInterval.Three || pi == PresentInterval.Four ) { // These intervals are not supported in windowed mode. continue; } } // Note that PresentInterval.Default is zero, so you // can't do a caps check for it -- it is always available. if (pi == PresentInterval.Default || (deviceInfo.Caps.PresentationIntervals & pi) != (PresentInterval)0) { deviceCombo.PresentIntervalList.Add( pi ); } } } }