/* * Copyright (c) 2007-2009 SlimDX Group * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ using System; using System.Collections.Generic; using SharpDX.Direct3D9; namespace SampleFramework { class Direct3D9Settings : ICloneable { public int AdapterOrdinal { get; set; } public DeviceType DeviceType { get; set; } public Format AdapterFormat { get; set; } public CreateFlags CreationFlags { get; set; } public PresentParameters PresentParameters { get; set; } public Direct3D9Settings() { DeviceType = DeviceType.Hardware; AdapterFormat = Format.Unknown; CreationFlags = CreateFlags.HardwareVertexProcessing; var pp = new PresentParameters(); pp.Windowed = true; pp.BackBufferFormat = Format.Unknown; pp.BackBufferCount = 1; pp.MultiSampleType = MultisampleType.None; pp.SwapEffect = SwapEffect.Discard; pp.EnableAutoDepthStencil = true; pp.AutoDepthStencilFormat = Format.Unknown; pp.PresentFlags = PresentFlags.DiscardDepthStencil; pp.PresentationInterval = PresentInterval.Default; this.PresentParameters = pp; } public Direct3D9Settings Clone() { Direct3D9Settings clone = new Direct3D9Settings(); clone.AdapterFormat = AdapterFormat; clone.AdapterOrdinal = AdapterOrdinal; clone.CreationFlags = CreationFlags; clone.DeviceType = DeviceType; clone.PresentParameters = PresentParameters; return clone; } object ICloneable.Clone() { return Clone(); } public static Direct3D9Settings BuildOptimalSettings(DeviceSettings settings) { DisplayMode desktopMode = GraphicsDeviceManager.Direct3D9Object.GetAdapterDisplayMode(0); Direct3D9Settings optimal = new Direct3D9Settings(); var pp = optimal.PresentParameters; optimal.AdapterOrdinal = settings.AdapterOrdinal; optimal.DeviceType = settings.DeviceType; pp.Windowed = settings.Windowed; pp.BackBufferCount = settings.BackBufferCount; pp.MultiSampleType = settings.MultisampleType; pp.MultiSampleQuality = settings.MultisampleQuality; pp.FullScreenRefreshRateInHz = settings.RefreshRate; if (settings.Multithreaded) optimal.CreationFlags |= CreateFlags.Multithreaded; if(optimal.PresentParameters.Windowed || ConversionMethods.GetColorBits(desktopMode.Format) >= 8) optimal.AdapterFormat = desktopMode.Format; else optimal.AdapterFormat = Format.X8R8G8B8; if(settings.BackBufferWidth == 0 || settings.BackBufferHeight == 0) { if(optimal.PresentParameters.Windowed) { pp.BackBufferWidth = 640; pp.BackBufferHeight = 480; } else { pp.BackBufferWidth = desktopMode.Width; pp.BackBufferHeight = desktopMode.Height; } } else { pp.BackBufferWidth = settings.BackBufferWidth; pp.BackBufferHeight = settings.BackBufferHeight; } if(settings.BackBufferFormat == Format.Unknown) pp.BackBufferFormat = optimal.AdapterFormat; else pp.BackBufferFormat = settings.BackBufferFormat; if(settings.DepthStencilFormat == Format.Unknown) { if(ConversionMethods.GetColorBits(optimal.PresentParameters.BackBufferFormat) >= 8) pp.AutoDepthStencilFormat = Format.D32; else pp.AutoDepthStencilFormat = Format.D16; } else pp.AutoDepthStencilFormat = settings.DepthStencilFormat; if(!settings.EnableVSync) pp.PresentationInterval = PresentInterval.Immediate; optimal.PresentParameters = pp; return optimal; } public static float RankSettingsCombo(SettingsCombo9 combo, Direct3D9Settings optimal, DisplayMode desktopMode) { float ranking = 0.0f; if(combo.AdapterOrdinal == optimal.AdapterOrdinal) ranking += 1000.0f; if(combo.DeviceType == optimal.DeviceType) ranking += 100.0f; if(combo.DeviceType == DeviceType.Hardware) ranking += 0.1f; if(combo.Windowed == optimal.PresentParameters.Windowed) ranking += 10.0f; if(combo.AdapterFormat == optimal.AdapterFormat) ranking += 1.0f; else { int bitDepthDelta = Math.Abs(ConversionMethods.GetColorBits(combo.AdapterFormat) - ConversionMethods.GetColorBits(optimal.AdapterFormat)); float scale = Math.Max(0.9f - bitDepthDelta * 0.2f, 0.0f); ranking += scale; } if(!combo.Windowed) { bool match; if(ConversionMethods.GetColorBits(desktopMode.Format) >= 8) match = (combo.AdapterFormat == desktopMode.Format); else match = (combo.AdapterFormat == Format.X8R8G8B8); if(match) ranking += 0.1f; } if((optimal.CreationFlags & CreateFlags.HardwareVertexProcessing) != 0 && (optimal.CreationFlags & CreateFlags.MixedVertexProcessing) != 0) { if((combo.DeviceInfo.Capabilities.DeviceCaps & DeviceCaps.HWTransformAndLight) != 0) ranking += 1.0f; } if((combo.DeviceInfo.Capabilities.DeviceCaps & DeviceCaps.HWTransformAndLight) != 0) ranking += 0.1f; foreach(DisplayMode displayMode in combo.AdapterInfo.DisplayModes) { if(displayMode.Format == combo.AdapterFormat && displayMode.Width == optimal.PresentParameters.BackBufferWidth && displayMode.Height == optimal.PresentParameters.BackBufferHeight) { ranking += 1.0f; break; } } if(combo.BackBufferFormat == optimal.PresentParameters.BackBufferFormat) ranking += 1.0f; else { int bitDepthDelta = Math.Abs(ConversionMethods.GetColorBits(combo.BackBufferFormat) - ConversionMethods.GetColorBits(optimal.PresentParameters.BackBufferFormat)); float scale = Math.Max(0.9f - bitDepthDelta * 0.2f, 0.0f); ranking += scale; } if(combo.BackBufferFormat == combo.AdapterFormat) ranking += 0.1f; for(int i = 0; i < combo.MultisampleTypes.Count; i++) { MultisampleType type = combo.MultisampleTypes[i]; int quality = combo.MultisampleQualities[i]; if(type == optimal.PresentParameters.MultiSampleType && quality == optimal.PresentParameters.MultiSampleQuality) { ranking += 1.0f; break; } } if(combo.DepthStencilFormats.Contains(optimal.PresentParameters.AutoDepthStencilFormat)) ranking += 1.0f; foreach(DisplayMode displayMode in combo.AdapterInfo.DisplayModes) { if(displayMode.Format == combo.AdapterFormat && displayMode.RefreshRate == optimal.PresentParameters.FullScreenRefreshRateInHz) { ranking += 1.0f; break; } } if(combo.PresentIntervals.Contains(optimal.PresentParameters.PresentationInterval)) ranking += 1.0f; return ranking; } public static Direct3D9Settings BuildValidSettings(SettingsCombo9 combo, Direct3D9Settings input) { Direct3D9Settings settings = new Direct3D9Settings(); var pp = settings.PresentParameters; settings.AdapterOrdinal = combo.AdapterOrdinal; settings.DeviceType = combo.DeviceType; settings.AdapterFormat = combo.AdapterFormat; pp.Windowed = combo.Windowed; pp.BackBufferFormat = combo.BackBufferFormat; pp.SwapEffect = input.PresentParameters.SwapEffect; pp.PresentFlags = input.PresentParameters.PresentFlags | PresentFlags.DiscardDepthStencil; settings.CreationFlags = input.CreationFlags; if((combo.DeviceInfo.Capabilities.DeviceCaps & DeviceCaps.HWTransformAndLight) == 0 && ((settings.CreationFlags & CreateFlags.HardwareVertexProcessing) != 0 || (settings.CreationFlags & CreateFlags.MixedVertexProcessing) != 0)) { settings.CreationFlags &= ~CreateFlags.HardwareVertexProcessing; settings.CreationFlags &= ~CreateFlags.MixedVertexProcessing; settings.CreationFlags |= CreateFlags.SoftwareVertexProcessing; } if((settings.CreationFlags & CreateFlags.HardwareVertexProcessing) == 0 && (settings.CreationFlags & CreateFlags.MixedVertexProcessing) == 0 && (settings.CreationFlags & CreateFlags.SoftwareVertexProcessing) == 0) { if((combo.DeviceInfo.Capabilities.DeviceCaps & DeviceCaps.HWTransformAndLight) != 0) settings.CreationFlags |= CreateFlags.HardwareVertexProcessing; else settings.CreationFlags |= CreateFlags.SoftwareVertexProcessing; } DisplayMode bestDisplayMode = FindValidResolution(combo, input); pp.BackBufferWidth = bestDisplayMode.Width; pp.BackBufferHeight = bestDisplayMode.Height; pp.BackBufferCount = input.PresentParameters.BackBufferCount; if(pp.BackBufferCount > 3) pp.BackBufferCount = 3; if(pp.BackBufferCount < 1) pp.BackBufferCount = 1; if(input.PresentParameters.SwapEffect != SwapEffect.Discard) { pp.MultiSampleType = MultisampleType.None; pp.MultiSampleQuality = 0; } else { MultisampleType bestType = MultisampleType.None; int bestQuality = 0; for(int i = 0; i < combo.MultisampleTypes.Count; i++) { MultisampleType type = combo.MultisampleTypes[i]; int quality = combo.MultisampleQualities[i]; if(Math.Abs(type - input.PresentParameters.MultiSampleType) < Math.Abs(bestType - input.PresentParameters.MultiSampleType)) { bestType = type; bestQuality = Math.Min(quality - 1, input.PresentParameters.MultiSampleQuality); } } pp.MultiSampleType = bestType; pp.MultiSampleQuality = bestQuality; } List rankings = new List(); int inputDepthBitDepth = ConversionMethods.GetDepthBits(input.PresentParameters.AutoDepthStencilFormat); int inputStencilBitDepth = ConversionMethods.GetStencilBits(input.PresentParameters.AutoDepthStencilFormat); foreach(Format format in combo.DepthStencilFormats) { int currentBitDepth = ConversionMethods.GetDepthBits(format); int currentStencilDepth = ConversionMethods.GetStencilBits(format); int ranking = Math.Abs(currentBitDepth - inputDepthBitDepth); ranking += Math.Abs(currentStencilDepth - inputStencilBitDepth); rankings.Add(ranking); } int bestRanking = int.MaxValue; foreach(int ranking in rankings) { if(ranking < bestRanking) bestRanking = ranking; } int bestIndex = rankings.IndexOf(bestRanking); if(bestIndex >= 0) { pp.AutoDepthStencilFormat = combo.DepthStencilFormats[bestIndex]; pp.EnableAutoDepthStencil = true; } else { pp.AutoDepthStencilFormat = Format.Unknown; pp.EnableAutoDepthStencil = false; } if(combo.Windowed) pp.FullScreenRefreshRateInHz = 0; else { int match = input.PresentParameters.FullScreenRefreshRateInHz; bestDisplayMode.RefreshRate = 0; if(match != 0) { bestRanking = 100000; foreach(DisplayMode displayMode in combo.AdapterInfo.DisplayModes) { if(displayMode.Format != combo.AdapterFormat || displayMode.Width != bestDisplayMode.Width || displayMode.Height != bestDisplayMode.Height) continue; int ranking = Math.Abs(displayMode.RefreshRate - match); if(ranking < bestRanking) { bestDisplayMode.RefreshRate = displayMode.RefreshRate; bestRanking = ranking; if(bestRanking == 0) break; } } } pp.FullScreenRefreshRateInHz = bestDisplayMode.RefreshRate; } if(combo.PresentIntervals.Contains(input.PresentParameters.PresentationInterval)) pp.PresentationInterval = input.PresentParameters.PresentationInterval; else pp.PresentationInterval = PresentInterval.Default; settings.PresentParameters = pp; return settings; } static DisplayMode FindValidResolution(SettingsCombo9 combo, Direct3D9Settings input) { DisplayMode bestMode = new DisplayMode(); if(combo.Windowed) { bestMode.Width = input.PresentParameters.BackBufferWidth; bestMode.Height = input.PresentParameters.BackBufferHeight; return bestMode; } int bestRanking = 100000; int ranking; foreach(DisplayMode mode in combo.AdapterInfo.DisplayModes) { if(mode.Format != combo.AdapterFormat) continue; ranking = Math.Abs(mode.Width - input.PresentParameters.BackBufferWidth) + Math.Abs(mode.Height - input.PresentParameters.BackBufferHeight); if(ranking < bestRanking) { bestMode = mode; bestRanking = ranking; if(bestRanking == 0) break; } } if(bestMode.Width == 0) { bestMode.Width = input.PresentParameters.BackBufferWidth; bestMode.Height = input.PresentParameters.BackBufferHeight; } return bestMode; } } }