diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index ec526fa1..05200297 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -2,7 +2,7 @@ // // The Open Toolkit Library License // -// Copyright (c) 2006 - 2009 the Open Toolkit library. +// Copyright (c) 2006 - 2010 the Open Toolkit library. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,23 +28,20 @@ using System; using System.Collections.Generic; using System.Text; -using System.Windows.Forms; using System.Diagnostics; using System.Runtime.InteropServices; using OpenTK.Graphics; -using ColorDepth = OpenTK.Graphics.ColorFormat; namespace OpenTK.Platform.Windows { internal class WinGraphicsMode : IGraphicsMode { - // Todo: Get rid of the System.Windows.Forms.Control dependency. - - #region --- Fields --- + #region Fields // To avoid recursion when calling GraphicsMode.Default bool creating; + readonly List modes = new List(); static readonly object SyncRoot = new object(); #endregion @@ -52,127 +49,135 @@ namespace OpenTK.Platform.Windows #region --- Constructors --- public WinGraphicsMode() - { - } - - #endregion - - #region --- IGraphicsMode Members --- - - public GraphicsMode SelectGraphicsMode(ColorDepth color, int depth, int stencil, int samples, ColorDepth accum, - int buffers, bool stereo) { lock (SyncRoot) { - GraphicsMode mode = null; - if (!creating) + using (INativeWindow native = new NativeWindow()) { - creating = true; - try - { - mode = SelectGraphicsModeARB(color, depth, stencil, samples, accum, buffers, stereo); - } - finally - { - if (mode == null) - mode = SelectGraphicsModePFD(color, depth, stencil, samples, accum, buffers, stereo); - } + modes.AddRange(GetModesARB(native)); + if (modes.Count == 0) + modes.AddRange(GetModesPFD(native)); } - - creating = false; - return mode; + modes.Sort(new GraphicsModeComparer()); } } #endregion - #region --- Private Methods --- + #region IGraphicsMode Members - #region SelectGraphicsModePFD - - GraphicsMode SelectGraphicsModePFD(ColorDepth color, int depth, int stencil, int samples, ColorDepth accum, - int buffers, bool stereo) + public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, int samples, + ColorFormat accum, int buffers, bool stereo) { - using (INativeWindow native_window = new NativeWindow()) + GraphicsMode mode = null; + do { - WinWindowInfo window = native_window.WindowInfo as WinWindowInfo; - IntPtr deviceContext = ((WinWindowInfo)window).DeviceContext; - Debug.WriteLine(String.Format("Device context: {0}", deviceContext)); - - Debug.Write("Selecting pixel format (PFD)... "); - PixelFormatDescriptor pixelFormat = new PixelFormatDescriptor(); - pixelFormat.Size = API.PixelFormatDescriptorSize; - pixelFormat.Version = API.PixelFormatDescriptorVersion; - pixelFormat.Flags = - PixelFormatDescriptorFlags.SUPPORT_OPENGL | - PixelFormatDescriptorFlags.DRAW_TO_WINDOW; - pixelFormat.ColorBits = (byte)(color.Red + color.Green + color.Blue); - - pixelFormat.PixelType = color.IsIndexed ? PixelType.INDEXED : PixelType.RGBA; - pixelFormat.RedBits = (byte)color.Red; - pixelFormat.GreenBits = (byte)color.Green; - pixelFormat.BlueBits = (byte)color.Blue; - pixelFormat.AlphaBits = (byte)color.Alpha; - - if (accum.BitsPerPixel > 0) + mode = modes.Find(delegate(GraphicsMode current) { - pixelFormat.AccumBits = (byte)(accum.Red + accum.Green + accum.Blue); - pixelFormat.AccumRedBits = (byte)accum.Red; - pixelFormat.AccumGreenBits = (byte)accum.Green; - pixelFormat.AccumBlueBits = (byte)accum.Blue; - pixelFormat.AccumAlphaBits = (byte)accum.Alpha; + return ModeSelector(current, color, depth, stencil, samples, accum, buffers, stereo); + }); + } while (mode == null && RelaxParameters( + ref color, ref depth, ref stencil, ref samples, ref accum, ref buffers, ref stereo)); + + return mode; + } + + bool RelaxParameters(ref ColorFormat color, ref int depth, ref int stencil, ref int samples, + ref ColorFormat accum, ref int buffers, ref bool stereo) + { + if (stereo) { stereo = false; return true; } + if (buffers != 2) { buffers = 2; return true; } + if (accum != 0) { accum = 0; return true; } + if (samples != 0) { samples = 0; return true; } + if (color == 32 && depth == 24 && stencil != 8) { color = 32; depth = 24; stencil = 8; return true; } + if (color == 32 && depth == 24 && stencil == 8) { color = 32; depth = 24; stencil = 0; return true; } + if (color == 32 && depth != 16) { color = 32; depth = 16; stencil = 0; return true; } + if (color == 24 && depth == 24 && stencil != 8) { color = 24; depth = 24; stencil = 8; return true; } + if (color == 24 && depth == 24 && stencil == 8) { color = 24; depth = 24; stencil = 0; return true; } + if (color == 24 && depth != 16) { color = 24; depth = 16; stencil = 0; return true; } + if (color == 16 && depth == 24 && stencil != 8) { color = 16; depth = 24; stencil = 8; return true; } + if (color == 16 && depth == 24 && stencil == 8) { color = 16; depth = 24; stencil = 0; return true; } + if (color == 16 && depth != 16) { color = 16; depth = 16; stencil = 0; return true; } + if (color < 16) { color = 16; return true; } + return false; + } + + #endregion + + #region Private Methods + + #region DescribePixelFormat + + static int DescribePixelFormat(IntPtr hdc, int ipfd, int cjpfd, ref PixelFormatDescriptor pfd) + { + unsafe + { + fixed (PixelFormatDescriptor* ppfd = &pfd) + { + // Note: DescribePixelFormat found in gdi32 is extremely slow + // on nvidia, for some reason. + return Wgl.Imports.DescribePixelFormat(hdc, ipfd, (uint)cjpfd, ppfd); } + } + } - pixelFormat.DepthBits = (byte)depth; - pixelFormat.StencilBits = (byte)stencil; + #endregion - if (depth <= 0) pixelFormat.Flags |= PixelFormatDescriptorFlags.DEPTH_DONTCARE; - if (stereo) pixelFormat.Flags |= PixelFormatDescriptorFlags.STEREO; - if (buffers > 1) pixelFormat.Flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER; + #region GetModesPFD - int pixel = Functions.ChoosePixelFormat(deviceContext, ref pixelFormat); - if (pixel == 0) - throw new GraphicsModeException("The requested GraphicsMode is not available."); + IEnumerable GetModesPFD(INativeWindow native) + { + WinWindowInfo window = native.WindowInfo as WinWindowInfo; + IntPtr deviceContext = ((WinWindowInfo)window).DeviceContext; + Debug.WriteLine(String.Format("Device context: {0}", deviceContext)); + + Debug.WriteLine("Retrieving PFD pixel formats... "); + PixelFormatDescriptor pfd = new PixelFormatDescriptor(); + pfd.Size = API.PixelFormatDescriptorSize; + pfd.Version = API.PixelFormatDescriptorVersion; + pfd.Flags = + PixelFormatDescriptorFlags.SUPPORT_OPENGL | + PixelFormatDescriptorFlags.DRAW_TO_WINDOW; + + int pixel = 0; + while (DescribePixelFormat(deviceContext, ++pixel, API.PixelFormatDescriptorSize, ref pfd) != 0) + { + // Ignore non-accelerated formats. + if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) + continue; - // Find out what we really got as a format: - PixelFormatDescriptor pfd = new PixelFormatDescriptor(); - pixelFormat.Size = API.PixelFormatDescriptorSize; - pixelFormat.Version = API.PixelFormatDescriptorVersion; - Functions.DescribePixelFormat(deviceContext, pixel, API.PixelFormatDescriptorSize, ref pfd); GraphicsMode fmt = new GraphicsMode((IntPtr)pixel, - new ColorDepth(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits), + new ColorFormat(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits), pfd.DepthBits, pfd.StencilBits, 0, - new ColorDepth(pfd.AccumBits), + new ColorFormat(pfd.AccumBits), (pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) != 0 ? 2 : 1, (pfd.Flags & PixelFormatDescriptorFlags.STEREO) != 0); - return fmt; + yield return fmt; } } #endregion - #region SelectGraphicsModeARB + #region GetModesARB - GraphicsMode SelectGraphicsModeARB(ColorDepth color, int depth, int stencil, int samples, ColorDepth accum, - int buffers, bool stereo) + IEnumerable GetModesARB(INativeWindow native) { - using (INativeWindow native_window = new NativeWindow()) - using (IGraphicsContext context = new WinGLContext( + using (IGraphicsContext context = new GraphicsContext( new GraphicsMode(new IntPtr(2), new ColorFormat(), 0, 0, 0, new ColorFormat(), 2, false), - (WinWindowInfo)native_window.WindowInfo, null, 1, 0, GraphicsContextFlags.Default)) + (WinWindowInfo)native.WindowInfo, 1, 0, GraphicsContextFlags.Default)) { - WinWindowInfo window = (WinWindowInfo)native_window.WindowInfo; + WinWindowInfo window = (WinWindowInfo)native.WindowInfo; - // See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt + // See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt // for more details - Debug.Write("Selecting pixel format (ARB)... "); + Debug.Write("Retrieving ARB pixel formats.... "); if (Wgl.Delegates.wglChoosePixelFormatARB == null || Wgl.Delegates.wglGetPixelFormatAttribivARB == null) { - Debug.WriteLine("failed"); - return null; + Debug.WriteLine("failed."); + yield break; } int[] attribs = new int[] @@ -206,73 +211,61 @@ namespace OpenTK.Platform.Windows int[] attribs_values = new int[] { - (int)WGL_ARB_pixel_format.AccelerationArb, (int)WGL_ARB_pixel_format.FullAccelerationArb, - (int)WGL_ARB_pixel_format.DrawToWindowArb, 1, - - (int)WGL_ARB_pixel_format.RedBitsArb, color.Red, - (int)WGL_ARB_pixel_format.GreenBitsArb, color.Green, - (int)WGL_ARB_pixel_format.BlueBitsArb, color.Blue, - (int)WGL_ARB_pixel_format.AlphaBitsArb, color.Alpha, - (int)WGL_ARB_pixel_format.ColorBitsArb, color.BitsPerPixel - color.Alpha, // Should not contain alpha bpp (see spec) - - (int)WGL_ARB_pixel_format.DepthBitsArb, depth, - (int)WGL_ARB_pixel_format.StencilBitsArb, stencil, - - (int)WGL_ARB_multisample.SampleBuffersArb, samples > 0 ? 1 : 0, - (int)WGL_ARB_multisample.SamplesArb, samples, - - (int)WGL_ARB_pixel_format.AccumRedBitsArb, accum.Red, - (int)WGL_ARB_pixel_format.AccumGreenBitsArb, accum.Green, - (int)WGL_ARB_pixel_format.AccumBlueBitsArb, accum.Blue, - (int)WGL_ARB_pixel_format.AccumAlphaBitsArb, accum.Alpha, - (int)WGL_ARB_pixel_format.AccumBitsArb, accum.BitsPerPixel, // Spec doesn't mention wether alpha bpp should be included... - - (int)WGL_ARB_pixel_format.DoubleBufferArb, buffers > 1 ? 1 : 0, - (int)WGL_ARB_pixel_format.StereoArb, stereo ? 1 : 0, + (int)WGL_ARB_pixel_format.AccelerationArb, + (int)WGL_ARB_pixel_format.FullAccelerationArb, 0, 0 }; - int[] pixel = new int[1], num_formats = new int[1]; - bool success = Wgl.Arb.ChoosePixelFormat(window.DeviceContext, attribs_values, null, 1, pixel, num_formats); - if (!success || num_formats[0] == 0 || pixel[0] == 0) - { - // Try again without an accumulator. Many modern cards cannot accelerate multisampled formats with accumulator buffers. - int index_of_accum = Array.IndexOf(attribs_values, (int)WGL_ARB_pixel_format.AccumRedBitsArb); - attribs_values[index_of_accum + 1] = attribs_values[index_of_accum + 3] = - attribs_values[index_of_accum + 5] = attribs_values[index_of_accum + 7] = - attribs_values[index_of_accum + 9] = 0; - Wgl.Arb.ChoosePixelFormat(window.DeviceContext, attribs_values, null, 1, pixel, num_formats); - } - if (!success || num_formats[0] == 0 || pixel[0] == 0) - { - Debug.WriteLine("failed (no suitable pixel format)."); - return null; - } + int[] num_formats = new int[1]; + Wgl.Arb.ChoosePixelFormat(window.DeviceContext, attribs_values, null, 0, null, num_formats); + int[] pixel = new int[num_formats[0]]; - // Find out what we really got as a format: - success = Wgl.Arb.GetPixelFormatAttrib(window.DeviceContext, pixel[0], 0, attribs.Length - 1, attribs, values); - if (!success) + if (Wgl.Arb.ChoosePixelFormat(window.DeviceContext, attribs_values, null, pixel.Length, pixel, num_formats)) { - Debug.WriteLine("failed (pixel format attributes could not be determined)."); - return null; + foreach (int p in pixel) + { + // Find out what we really got as a format: + if (!Wgl.Arb.GetPixelFormatAttrib(window.DeviceContext, p, 0, attribs.Length - 1, attribs, values)) + { + Debug.Print("[Warning] Failed to detect attributes for PixelFormat:{0}.", p); + continue; + } + + GraphicsMode mode = new GraphicsMode(new IntPtr(p), + new ColorFormat(values[1], values[2], values[3], values[4]), + values[6], + values[7], + values[8] != 0 ? values[9] : 0, + new ColorFormat(values[10], values[11], values[12], values[13]), + values[15] == 1 ? 2 : 1, + values[16] == 1 ? true : false); + + yield return mode; + } } - - GraphicsMode mode = new GraphicsMode(new IntPtr(pixel[0]), - new ColorDepth(values[1], values[2], values[3], values[4]), - values[6], - values[7], - values[8] != 0 ? values[9] : 0, - new ColorDepth(values[10], values[11], values[12], values[13]), - values[15] == 1 ? 2 : 1, - values[16] == 1 ? true : false); - - Debug.WriteLine("success!"); - return mode; } } #endregion + #region ModeSelector + + bool ModeSelector(GraphicsMode current, ColorFormat color, int depth, int stencil, int samples, + ColorFormat accum, int buffers, bool stereo) + { + bool result = + (color != ColorFormat.Empty ? current.ColorFormat >= color : true) && + (depth != 0 ? current.Depth >= depth : true) && + (stencil != 0 ? current.Stencil >= stencil : true) && + (samples != 0 ? current.Samples >= samples : true) && + (accum != ColorFormat.Empty ? current.AccumulatorFormat >= accum : true) && + (buffers != 0 ? current.Buffers >= buffers : true) && + current.Stereo == stereo; + return result; + } + + #endregion + #endregion } }