From 4aa2eae2e56e212b2bf543040e0dfd0b92d0479b Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sat, 21 Dec 2013 22:41:10 +0100 Subject: [PATCH 1/7] Display renderer information --- Source/Examples/OpenTK/Test/GameWindowStates.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index 73d81002..cdb5afa2 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -218,7 +218,10 @@ namespace Examples.Tests gfx.Clear(Color.Black); gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; - + + DrawString(gfx, GL.GetString(StringName.Vendor), line++); + DrawString(gfx, GL.GetString(StringName.Version), line++); + DrawString(gfx, GL.GetString(StringName.Renderer), line++); DrawString(gfx, Context.GraphicsMode.ToString(), line++); DrawString(gfx, String.Format("[1 - 4]: change WindowState (current: {0}).", this.WindowState), line++); From a7ae4bb038ff3a2d95f75114a658ed549ef699ec Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sat, 21 Dec 2013 22:41:35 +0100 Subject: [PATCH 2/7] Turn 1-element array to ref/out param --- Source/OpenTK/Platform/Windows/Bindings/Wgl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs b/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs index e235beb8..e1bd92ad 100644 --- a/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs +++ b/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs @@ -202,14 +202,14 @@ namespace OpenTK.Platform.Windows } public static - Boolean ChoosePixelFormat(IntPtr hdc, int[] piAttribIList, Single[] pfAttribFList, Int32 nMaxFormats, [Out] int[] piFormats, [Out] Int32[] nNumFormats) + Boolean ChoosePixelFormat(IntPtr hdc, int[] piAttribIList, Single[] pfAttribFList, Int32 nMaxFormats, [Out] int[] piFormats, out int nNumFormats) { unsafe { fixed (int* piAttribIList_ptr = piAttribIList) fixed (Single* pfAttribFList_ptr = pfAttribFList) fixed (int* piFormats_ptr = piFormats) - fixed (Int32* nNumFormats_ptr = nNumFormats) + fixed (Int32* nNumFormats_ptr = &nNumFormats) { return Delegates.wglChoosePixelFormatARB((IntPtr)hdc, (int*)piAttribIList_ptr, (Single*)pfAttribFList_ptr, (UInt32)nMaxFormats, (int*)piFormats_ptr, (UInt32*)nNumFormats_ptr); } From 1723be8a8b52532174085214145e73e5399f76aa Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sat, 21 Dec 2013 22:43:35 +0100 Subject: [PATCH 3/7] Prioritize accelerated formats first Instead of creating a list of all available formats and iterating through that, we let the driver decide which is the best accelerated format to use for the user parameters. If no such format exists, we fall back to generic acceleration or software acceleration, in turn. This affects issue #21 --- .../Platform/Windows/WinGraphicsMode.cs | 410 +++++++++++------- 1 file changed, 250 insertions(+), 160 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index 0efc07ce..e7cf613e 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -37,27 +37,28 @@ namespace OpenTK.Platform.Windows { class WinGraphicsMode : IGraphicsMode { - #region Fields + enum AccelerationType + { + // Software acceleration + None = 0, + // Partial acceleration (Direct3D emulation) + MCD, + // Full acceleration + ICD, + } - readonly List modes = new List(); static readonly object SyncRoot = new object(); - - #endregion + readonly IntPtr Device; + readonly List modes = new List(); #region Constructors public WinGraphicsMode(IntPtr device) { - lock (SyncRoot) - { - modes.AddRange(GetModesARB(device)); - if (modes.Count == 0) - modes.AddRange(GetModesPFD(device)); - if (modes.Count == 0) - throw new GraphicsModeException( - "No GraphicsMode available. This should never happen, please report a bug at http://www.opentk.com"); - modes.Sort(new GraphicsModeComparer()); - } + if (device == IntPtr.Zero) + throw new ArgumentException(); + + Device = device; } #endregion @@ -67,57 +68,172 @@ namespace OpenTK.Platform.Windows public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, int buffers, bool stereo) { - GraphicsMode mode = null; - do + GraphicsMode mode = new GraphicsMode(color, depth, stencil, samples,accum, buffers, stereo); + GraphicsMode created_mode = ChoosePixelFormatARB(Device, mode); + + // If ChoosePixelFormatARB failed, iterate through all acceleration types in turn (ICD, MCD, None) + // This should fix issue #2224, which causes OpenTK to fail on VMs without hardware acceleration. + created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.ICD); + created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.MCD); + created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.None); + + if (created_mode == null) { - mode = modes.Find(delegate(GraphicsMode current) - { - 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)); + throw new GraphicsModeException("The requested GraphicsMode is not supported"); + } - if (mode == null) - mode = modes[0]; - - 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 (depth < 16) { depth = 16; return true; } - if (depth != 24) { depth = 24; return true; } - if (stencil > 0 && stencil != 8) { stencil = 8; return true; } - if (stencil == 8) { stencil = 0; return true; } - if (color < 8) { color = 8; return true; } - if (color < 16) { color = 16; return true; } - if (color < 24) { color = 24; return true; } - if (color < 32 || color > 32) { color = 32; return true; } - return false; // We tried everything we could, no match found. + return created_mode; } #endregion #region Private Methods - #region GetModesPFD + #region ChoosePixelFormatARB - IEnumerable GetModesPFD(IntPtr device) + // Queries pixel formats through the WGL_ARB_pixel_format extension + // This method only returns accelerated formats. If no format offers + // hardware acceleration (e.g. we are running in a VM or in a remote desktop + // connection), this method will return 0 formats and we will fall back to + // ChoosePixelFormatPFD. + GraphicsMode ChoosePixelFormatARB(IntPtr device, GraphicsMode mode) { - Debug.WriteLine(String.Format("Device context: {0}", device)); + GraphicsMode created_mode = null; + if (Wgl.Delegates.wglChoosePixelFormatARB != null) + { + List attributes = new List(); + attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb); + attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb); - Debug.WriteLine("Retrieving PFD pixel formats... "); + if (mode.ColorFormat.BitsPerPixel > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.RedBitsArb); + attributes.Add(mode.ColorFormat.Red); + attributes.Add((int)WGL_ARB_pixel_format.GreenBitsArb); + attributes.Add(mode.ColorFormat.Green); + attributes.Add((int)WGL_ARB_pixel_format.BlueBitsArb); + attributes.Add(mode.ColorFormat.Blue); + attributes.Add((int)WGL_ARB_pixel_format.AlphaBitsArb); + attributes.Add(mode.ColorFormat.Alpha); + attributes.Add((int)WGL_ARB_pixel_format.ColorBitsArb); + attributes.Add(mode.ColorFormat.BitsPerPixel); + } + + if (mode.Depth > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.DepthBitsArb); + attributes.Add(mode.Depth); + } + + if (mode.Stencil > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.StencilBitsArb); + attributes.Add(mode.Stencil); + } + + if (mode.AccumulatorFormat.BitsPerPixel > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.AccumRedBitsArb); + attributes.Add(mode.AccumulatorFormat.Red); + attributes.Add((int)WGL_ARB_pixel_format.AccumGreenBitsArb); + attributes.Add(mode.AccumulatorFormat.Green); + attributes.Add((int)WGL_ARB_pixel_format.AccumBlueBitsArb); + attributes.Add(mode.AccumulatorFormat.Blue); + attributes.Add((int)WGL_ARB_pixel_format.AccumAlphaBitsArb); + attributes.Add(mode.AccumulatorFormat.Alpha); + attributes.Add((int)WGL_ARB_pixel_format.AccumBitsArb); + attributes.Add(mode.AccumulatorFormat.BitsPerPixel); + } + + if (mode.Samples > 0) + { + attributes.Add((int)WGL_ARB_multisample.SampleBuffersArb); + attributes.Add(1); + attributes.Add((int)WGL_ARB_multisample.SamplesArb); + attributes.Add(mode.Samples); + } + + if (mode.Buffers > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb); + attributes.Add(mode.Buffers); + } + + if (mode.Stereo) + { + attributes.Add((int)WGL_ARB_pixel_format.StereoArb); + attributes.Add(1); + } + + attributes.Add(0); + attributes.Add(0); + + int[] format = new int[1]; + int count; + if (Wgl.Arb.ChoosePixelFormat(device, attributes.ToArray(), null, format.Length, format, out count)) + { + created_mode = DescribePixelFormatARB(device, format[0]); + } + else + { + Debug.Print("[WGL] ChoosePixelFormatARB failed with {0}", Marshal.GetLastWin32Error()); + } + } + else + { + Debug.Print("[WGL] ChoosePixelFormatARB not supported"); + } + + return created_mode; + } + + #endregion + + #region ChoosePixelFormatPFD + + GraphicsMode ChoosePixelFormatPFD(IntPtr Device, GraphicsMode mode, AccelerationType requested_acceleration_type) + { PixelFormatDescriptor pfd = new PixelFormatDescriptor(); - pfd.Size = API.PixelFormatDescriptorSize; - pfd.Version = API.PixelFormatDescriptorVersion; - pfd.Flags = - PixelFormatDescriptorFlags.SUPPORT_OPENGL | - PixelFormatDescriptorFlags.DRAW_TO_WINDOW; + pfd.Size = (short)BlittableValueType.Stride; + + if (mode.ColorFormat.BitsPerPixel > 0) + { + pfd.RedBits = (byte)mode.ColorFormat.Red; + pfd.GreenBits = (byte)mode.ColorFormat.Green; + pfd.BlueBits = (byte)mode.ColorFormat.Blue; + pfd.AlphaBits = (byte)mode.ColorFormat.Alpha; + pfd.ColorBits = (byte)mode.ColorFormat.BitsPerPixel; + } + + if (mode.Depth > 0) + { + pfd.DepthBits = (byte)mode.Depth; + } + + if (mode.Stencil > 0) + { + pfd.StencilBits = (byte)mode.Stencil; + } + + if (mode.AccumulatorFormat.BitsPerPixel > 0) + { + pfd.AccumRedBits = (byte)mode.AccumulatorFormat.Red; + pfd.AccumGreenBits = (byte)mode.AccumulatorFormat.Green; + pfd.AccumBlueBits = (byte)mode.AccumulatorFormat.Blue; + pfd.AccumAlphaBits = (byte)mode.AccumulatorFormat.Alpha; + pfd.AccumBits = (byte)mode.AccumulatorFormat.BitsPerPixel; + } + + if (mode.Buffers > 0) + { + pfd.Flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER; + } + + if (mode.Stereo) + { + pfd.Flags |= PixelFormatDescriptorFlags.DRAW_TO_WINDOW; + pfd.Flags |= PixelFormatDescriptorFlags.SUPPORT_OPENGL; + } // Make sure we don't turn off Aero on Vista and newer. if (Environment.OSVersion.Version.Major >= 6) @@ -125,109 +241,102 @@ namespace OpenTK.Platform.Windows pfd.Flags |= PixelFormatDescriptorFlags.SUPPORT_COMPOSITION; } - foreach (bool generic_allowed in new bool[] { false, true }) + GraphicsMode created_mode = null; + int pixelformat = Functions.ChoosePixelFormat(Device, ref pfd); + if (pixelformat > 0) { - // Iterate through all accelerated formats first. Afterwards, iterate through non-accelerated formats. - // This should fix issue #2224, which causes OpenTK to fail on VMs without hardware acceleration. - // Note: DescribePixelFormat found in gdi32 is extremely slow on nvidia, for some reason. - int pixel = 0; - while (Functions.DescribePixelFormat(device, ++pixel, API.PixelFormatDescriptorSize, ref pfd) != 0) + AccelerationType acceleration_type = AccelerationType.ICD; + if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) { - // Ignore non-accelerated formats. - if (!generic_allowed && (pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) - continue; + if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_ACCELERATED) != 0) + { + acceleration_type = AccelerationType.MCD; + } + else + { + acceleration_type = AccelerationType.None; + } + } - GraphicsMode fmt = new GraphicsMode((IntPtr)pixel, - new ColorFormat(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits), - pfd.DepthBits, - pfd.StencilBits, - 0, - new ColorFormat(pfd.AccumBits), - (pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) != 0 ? 2 : 1, - (pfd.Flags & PixelFormatDescriptorFlags.STEREO) != 0); - - yield return fmt; + if (acceleration_type == requested_acceleration_type) + { + created_mode = DescribePixelFormatPFD(ref pfd, pixelformat); } } + return created_mode; } #endregion - #region GetModesARB + #region DescribePixelFormatPFD - // Queries pixel formats through the WGL_ARB_pixel_format extension - // This method only returns accelerated formats. If no format offers - // hardware acceleration (e.g. we are running in a VM or in a remote desktop - // connection), this method will return 0 formats and we will fall back to - // GetModesPFD. - IEnumerable GetModesARB(IntPtr device) + static GraphicsMode DescribePixelFormatPFD(ref PixelFormatDescriptor pfd, int pixelformat) { - // See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt - // for more details - Debug.Write("Retrieving ARB pixel formats.... "); - if (Wgl.Delegates.wglChoosePixelFormatARB == null || Wgl.Delegates.wglGetPixelFormatAttribivARB == null) + return new GraphicsMode( + new IntPtr(pixelformat), + new ColorFormat(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits), + pfd.DepthBits, + pfd.StencilBits, + 0, // MSAA not supported + new ColorFormat(pfd.AccumRedBits, pfd.AccumGreenBits, pfd.AccumBlueBits, pfd.AccumAlphaBits), + (pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) != 0 ? 2 : 1, + (pfd.Flags & PixelFormatDescriptorFlags.STEREO) != 0); + } + + #endregion + + #region DescribePixelFormatARB + + GraphicsMode DescribePixelFormatARB(IntPtr device, int pixelformat) + { + GraphicsMode created_mode = null; + // See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt for more details + if (Wgl.Delegates.wglGetPixelFormatAttribivARB != null) { - Debug.WriteLine("failed."); - yield break; - } - - // Define the list of attributes we are interested in. - // We will use each available pixel format for these - // attributes using GetPixelFormatAttrib. - // The results will be stored in the 'values' array below. - int[] attribs = new int[] - { - (int)WGL_ARB_pixel_format.AccelerationArb, - - (int)WGL_ARB_pixel_format.RedBitsArb, - (int)WGL_ARB_pixel_format.GreenBitsArb, - (int)WGL_ARB_pixel_format.BlueBitsArb, - (int)WGL_ARB_pixel_format.AlphaBitsArb, - (int)WGL_ARB_pixel_format.ColorBitsArb, - - (int)WGL_ARB_pixel_format.DepthBitsArb, - (int)WGL_ARB_pixel_format.StencilBitsArb, - - (int)WGL_ARB_multisample.SampleBuffersArb, - (int)WGL_ARB_multisample.SamplesArb, - - (int)WGL_ARB_pixel_format.AccumRedBitsArb, - (int)WGL_ARB_pixel_format.AccumGreenBitsArb, - (int)WGL_ARB_pixel_format.AccumBlueBitsArb, - (int)WGL_ARB_pixel_format.AccumAlphaBitsArb, - (int)WGL_ARB_pixel_format.AccumBitsArb, - - (int)WGL_ARB_pixel_format.DoubleBufferArb, - (int)WGL_ARB_pixel_format.StereoArb, - 0 - }; - - // Allocate storage for the results of GetPixelFormatAttrib queries - int[] values = new int[attribs.Length]; - - // Get the number of available formats - int num_formats; - int num_formats_attrib = (int)WGL_ARB_pixel_format.NumberPixelFormatsArb; - if (Wgl.Arb.GetPixelFormatAttrib(device, 0, 0, 1, ref num_formats_attrib, out num_formats)) - { - for (int p = 1; p < num_formats; p++) + // Define the list of attributes we are interested in. + // The results will be stored in the 'values' array below. + int[] attribs = new int[] { - // Get the format attributes for this pixel format - if (!Wgl.Arb.GetPixelFormatAttrib(device, p, 0, attribs.Length - 1, attribs, values)) - { - Debug.Print("[Warning] Failed to detect attributes for PixelFormat:{0}.", p); - continue; - } + (int)WGL_ARB_pixel_format.AccelerationArb, - // Skip formats that don't offer full hardware acceleration - WGL_ARB_pixel_format acceleration = (WGL_ARB_pixel_format)attribs[0]; - if (acceleration != WGL_ARB_pixel_format.FullAccelerationArb) - { - continue; - } + (int)WGL_ARB_pixel_format.RedBitsArb, + (int)WGL_ARB_pixel_format.GreenBitsArb, + (int)WGL_ARB_pixel_format.BlueBitsArb, + (int)WGL_ARB_pixel_format.AlphaBitsArb, + (int)WGL_ARB_pixel_format.ColorBitsArb, + + (int)WGL_ARB_pixel_format.DepthBitsArb, + (int)WGL_ARB_pixel_format.StencilBitsArb, + + (int)WGL_ARB_multisample.SampleBuffersArb, + (int)WGL_ARB_multisample.SamplesArb, + (int)WGL_ARB_pixel_format.AccumRedBitsArb, + (int)WGL_ARB_pixel_format.AccumGreenBitsArb, + (int)WGL_ARB_pixel_format.AccumBlueBitsArb, + (int)WGL_ARB_pixel_format.AccumAlphaBitsArb, + (int)WGL_ARB_pixel_format.AccumBitsArb, + + (int)WGL_ARB_pixel_format.DoubleBufferArb, + (int)WGL_ARB_pixel_format.StereoArb, + 0 + }; + + // Allocate storage for the results of GetPixelFormatAttrib queries + int[] values = new int[attribs.Length]; + + // Get the format attributes for this pixel format + if (!Wgl.Arb.GetPixelFormatAttrib(device, pixelformat, 0, attribs.Length - 1, attribs, values)) + { + Debug.Print("[Warning] Failed to detect attributes for PixelFormat: {0}.", pixelformat); + } + + // Skip formats that don't offer full hardware acceleration + WGL_ARB_pixel_format acceleration = (WGL_ARB_pixel_format)attribs[0]; + if (acceleration == WGL_ARB_pixel_format.FullAccelerationArb) + { // Construct a new GraphicsMode to describe this format - GraphicsMode mode = new GraphicsMode(new IntPtr(p), + created_mode = new GraphicsMode(new IntPtr(pixelformat), new ColorFormat(values[1], values[2], values[3], values[4]), values[6], values[7], @@ -235,28 +344,9 @@ namespace OpenTK.Platform.Windows new ColorFormat(values[10], values[11], values[12], values[13]), values[15] == 1 ? 2 : 1, values[16] == 1 ? true : false); - - yield 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; + return created_mode; } #endregion From 956bbe6491b3d3d51fbbe1a146673bc4f354cf24 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sat, 21 Dec 2013 23:35:55 +0100 Subject: [PATCH 4/7] Fixed DescribePixelFormatPFD When using the PFD codepath, we now call DescribePixelFormat to retrieve an exact interpretation of the pixel format selected by the driver. --- .../Platform/Windows/WinGraphicsMode.cs | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index e7cf613e..541c13ab 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -191,7 +191,7 @@ namespace OpenTK.Platform.Windows #region ChoosePixelFormatPFD - GraphicsMode ChoosePixelFormatPFD(IntPtr Device, GraphicsMode mode, AccelerationType requested_acceleration_type) + GraphicsMode ChoosePixelFormatPFD(IntPtr device, GraphicsMode mode, AccelerationType requested_acceleration_type) { PixelFormatDescriptor pfd = new PixelFormatDescriptor(); pfd.Size = (short)BlittableValueType.Stride; @@ -209,6 +209,10 @@ namespace OpenTK.Platform.Windows { pfd.DepthBits = (byte)mode.Depth; } + else + { + pfd.Flags |= PixelFormatDescriptorFlags.DEPTH_DONTCARE; + } if (mode.Stencil > 0) { @@ -224,10 +228,14 @@ namespace OpenTK.Platform.Windows pfd.AccumBits = (byte)mode.AccumulatorFormat.BitsPerPixel; } - if (mode.Buffers > 0) + if (mode.Buffers > 1) { pfd.Flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER; } + else if (mode.Buffers == 0) + { + pfd.Flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER_DONTCARE; + } if (mode.Stereo) { @@ -242,7 +250,7 @@ namespace OpenTK.Platform.Windows } GraphicsMode created_mode = null; - int pixelformat = Functions.ChoosePixelFormat(Device, ref pfd); + int pixelformat = Functions.ChoosePixelFormat(device, ref pfd); if (pixelformat > 0) { AccelerationType acceleration_type = AccelerationType.ICD; @@ -260,7 +268,7 @@ namespace OpenTK.Platform.Windows if (acceleration_type == requested_acceleration_type) { - created_mode = DescribePixelFormatPFD(ref pfd, pixelformat); + created_mode = DescribePixelFormatPFD(device, ref pfd, pixelformat); } } return created_mode; @@ -270,17 +278,22 @@ namespace OpenTK.Platform.Windows #region DescribePixelFormatPFD - static GraphicsMode DescribePixelFormatPFD(ref PixelFormatDescriptor pfd, int pixelformat) + static GraphicsMode DescribePixelFormatPFD(IntPtr device, ref PixelFormatDescriptor pfd, int pixelformat) { - return new GraphicsMode( - new IntPtr(pixelformat), - new ColorFormat(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits), - pfd.DepthBits, - pfd.StencilBits, - 0, // MSAA not supported - new ColorFormat(pfd.AccumRedBits, pfd.AccumGreenBits, pfd.AccumBlueBits, pfd.AccumAlphaBits), - (pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) != 0 ? 2 : 1, - (pfd.Flags & PixelFormatDescriptorFlags.STEREO) != 0); + GraphicsMode created_mode = null; + if (Functions.DescribePixelFormat(device, pixelformat, pfd.Size, ref pfd) > 0) + { + created_mode = new GraphicsMode( + new IntPtr(pixelformat), + new ColorFormat(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits), + pfd.DepthBits, + pfd.StencilBits, + 0, // MSAA not supported when using PixelFormatDescriptor + new ColorFormat(pfd.AccumRedBits, pfd.AccumGreenBits, pfd.AccumBlueBits, pfd.AccumAlphaBits), + (pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) != 0 ? 2 : 1, + (pfd.Flags & PixelFormatDescriptorFlags.STEREO) != 0); + } + return created_mode; } #endregion From a2744719d5191218d44aa10c6d8dec30a210d422 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 09:20:40 +0100 Subject: [PATCH 5/7] Improved WGL mode selection Fixed WGL_ARB_pixel_format attribute selection for doublebuffering, stereoscopic rendering and hardware acceleration. Implemented minimization strategy to select the optimal PixelFormatDescriptor in the fallback path. --- .../Platform/Windows/WinGraphicsMode.cs | 165 ++++++++++-------- 1 file changed, 94 insertions(+), 71 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index 541c13ab..a9544f71 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -105,18 +105,28 @@ namespace OpenTK.Platform.Windows attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb); attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb); - if (mode.ColorFormat.BitsPerPixel > 0) + if (mode.ColorFormat.Red > 0) { attributes.Add((int)WGL_ARB_pixel_format.RedBitsArb); attributes.Add(mode.ColorFormat.Red); + } + + if (mode.ColorFormat.Green > 0) + { attributes.Add((int)WGL_ARB_pixel_format.GreenBitsArb); attributes.Add(mode.ColorFormat.Green); + } + + if (mode.ColorFormat.Blue > 0) + { attributes.Add((int)WGL_ARB_pixel_format.BlueBitsArb); attributes.Add(mode.ColorFormat.Blue); + } + + if (mode.ColorFormat.Alpha > 0) + { attributes.Add((int)WGL_ARB_pixel_format.AlphaBitsArb); attributes.Add(mode.ColorFormat.Alpha); - attributes.Add((int)WGL_ARB_pixel_format.ColorBitsArb); - attributes.Add(mode.ColorFormat.BitsPerPixel); } if (mode.Depth > 0) @@ -131,18 +141,28 @@ namespace OpenTK.Platform.Windows attributes.Add(mode.Stencil); } - if (mode.AccumulatorFormat.BitsPerPixel > 0) + if (mode.AccumulatorFormat.Red > 0) { attributes.Add((int)WGL_ARB_pixel_format.AccumRedBitsArb); attributes.Add(mode.AccumulatorFormat.Red); + } + + if (mode.AccumulatorFormat.Green > 0) + { attributes.Add((int)WGL_ARB_pixel_format.AccumGreenBitsArb); attributes.Add(mode.AccumulatorFormat.Green); + } + + if (mode.AccumulatorFormat.Blue > 0) + { attributes.Add((int)WGL_ARB_pixel_format.AccumBlueBitsArb); attributes.Add(mode.AccumulatorFormat.Blue); + } + + if (mode.AccumulatorFormat.Alpha > 0) + { attributes.Add((int)WGL_ARB_pixel_format.AccumAlphaBitsArb); attributes.Add(mode.AccumulatorFormat.Alpha); - attributes.Add((int)WGL_ARB_pixel_format.AccumBitsArb); - attributes.Add(mode.AccumulatorFormat.BitsPerPixel); } if (mode.Samples > 0) @@ -156,13 +176,11 @@ namespace OpenTK.Platform.Windows if (mode.Buffers > 0) { attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb); - attributes.Add(mode.Buffers); } if (mode.Stereo) { attributes.Add((int)WGL_ARB_pixel_format.StereoArb); - attributes.Add(1); } attributes.Add(0); @@ -181,7 +199,7 @@ namespace OpenTK.Platform.Windows } else { - Debug.Print("[WGL] ChoosePixelFormatARB not supported"); + Debug.WriteLine("[WGL] ChoosePixelFormatARB not supported on this context"); } return created_mode; @@ -191,94 +209,99 @@ namespace OpenTK.Platform.Windows #region ChoosePixelFormatPFD - GraphicsMode ChoosePixelFormatPFD(IntPtr device, GraphicsMode mode, AccelerationType requested_acceleration_type) + static bool Compare(int got, int requested, ref int distance) { - PixelFormatDescriptor pfd = new PixelFormatDescriptor(); - pfd.Size = (short)BlittableValueType.Stride; - - if (mode.ColorFormat.BitsPerPixel > 0) + if (got < requested) { - pfd.RedBits = (byte)mode.ColorFormat.Red; - pfd.GreenBits = (byte)mode.ColorFormat.Green; - pfd.BlueBits = (byte)mode.ColorFormat.Blue; - pfd.AlphaBits = (byte)mode.ColorFormat.Alpha; - pfd.ColorBits = (byte)mode.ColorFormat.BitsPerPixel; - } - - if (mode.Depth > 0) - { - pfd.DepthBits = (byte)mode.Depth; + return false; } else { - pfd.Flags |= PixelFormatDescriptorFlags.DEPTH_DONTCARE; + distance += got - requested; + return true; } + } - if (mode.Stencil > 0) + static AccelerationType GetAccelerationType(ref PixelFormatDescriptor pfd) + { + AccelerationType type = AccelerationType.ICD; + if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) { - pfd.StencilBits = (byte)mode.Stencil; + if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_ACCELERATED) != 0) + { + type = AccelerationType.MCD; + } + else + { + type = AccelerationType.None; + } } + return type; + } - if (mode.AccumulatorFormat.BitsPerPixel > 0) - { - pfd.AccumRedBits = (byte)mode.AccumulatorFormat.Red; - pfd.AccumGreenBits = (byte)mode.AccumulatorFormat.Green; - pfd.AccumBlueBits = (byte)mode.AccumulatorFormat.Blue; - pfd.AccumAlphaBits = (byte)mode.AccumulatorFormat.Alpha; - pfd.AccumBits = (byte)mode.AccumulatorFormat.BitsPerPixel; - } - - if (mode.Buffers > 1) - { - pfd.Flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER; - } - else if (mode.Buffers == 0) - { - pfd.Flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER_DONTCARE; - } + GraphicsMode ChoosePixelFormatPFD(IntPtr device, GraphicsMode mode, AccelerationType requested_acceleration_type) + { + PixelFormatDescriptor pfd = new PixelFormatDescriptor(); + PixelFormatDescriptorFlags flags = 0; + flags |= PixelFormatDescriptorFlags.DRAW_TO_WINDOW; + flags |= PixelFormatDescriptorFlags.SUPPORT_OPENGL; if (mode.Stereo) { - pfd.Flags |= PixelFormatDescriptorFlags.DRAW_TO_WINDOW; - pfd.Flags |= PixelFormatDescriptorFlags.SUPPORT_OPENGL; + flags |= PixelFormatDescriptorFlags.STEREO; + } + if (mode.Buffers > 1) + { + // On Win7 64bit + Nvidia 650M, no pixel format advertises DOUBLEBUFFER. + // Adding this check here causes mode selection to fail. + // Does not appear to be supported by DescribePixelFormat + //flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER; + } + if (System.Environment.OSVersion.Version.Major >= 6) + { + flags |= PixelFormatDescriptorFlags.SUPPORT_COMPOSITION; } - // Make sure we don't turn off Aero on Vista and newer. - if (Environment.OSVersion.Version.Major >= 6) - { - pfd.Flags |= PixelFormatDescriptorFlags.SUPPORT_COMPOSITION; - } + int count = Functions.DescribePixelFormat(device, 1, API.PixelFormatDescriptorSize, ref pfd); - GraphicsMode created_mode = null; - int pixelformat = Functions.ChoosePixelFormat(device, ref pfd); - if (pixelformat > 0) + int best = 0; + int best_dist = int.MaxValue; + for (int index = 1; index <= count; index++) { - AccelerationType acceleration_type = AccelerationType.ICD; - if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) - { - if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_ACCELERATED) != 0) - { - acceleration_type = AccelerationType.MCD; - } - else - { - acceleration_type = AccelerationType.None; - } - } + int dist = 0; + bool valid = Functions.DescribePixelFormat(device, index, API.PixelFormatDescriptorSize, ref pfd) != 0; + valid &= GetAccelerationType(ref pfd) == requested_acceleration_type; + valid &= (pfd.Flags & flags) == flags; + valid &= pfd.PixelType == PixelType.RGBA; // indexed modes not currently supported + valid &= Compare(pfd.ColorBits, mode.ColorFormat.BitsPerPixel, ref dist); + valid &= Compare(pfd.RedBits, mode.ColorFormat.Red, ref dist); + valid &= Compare(pfd.GreenBits, mode.ColorFormat.Green, ref dist); + valid &= Compare(pfd.BlueBits, mode.ColorFormat.Blue, ref dist); + valid &= Compare(pfd.AlphaBits, mode.ColorFormat.Alpha, ref dist); + valid &= Compare(pfd.AccumBits, mode.AccumulatorFormat.BitsPerPixel, ref dist); + valid &= Compare(pfd.AccumRedBits, mode.AccumulatorFormat.Red, ref dist); + valid &= Compare(pfd.AccumGreenBits, mode.AccumulatorFormat.Green, ref dist); + valid &= Compare(pfd.AccumBlueBits, mode.AccumulatorFormat.Blue, ref dist); + valid &= Compare(pfd.AccumAlphaBits, mode.AccumulatorFormat.Alpha, ref dist); + valid &= Compare(pfd.DepthBits, mode.Depth, ref dist); + valid &= Compare(pfd.StencilBits, mode.Stencil, ref dist); - if (acceleration_type == requested_acceleration_type) + if (valid && dist < best_dist) { - created_mode = DescribePixelFormatPFD(device, ref pfd, pixelformat); + best = index; + best_dist = dist; } } - return created_mode; + + return DescribePixelFormatPFD(device, ref pfd, best); } #endregion #region DescribePixelFormatPFD - static GraphicsMode DescribePixelFormatPFD(IntPtr device, ref PixelFormatDescriptor pfd, int pixelformat) + static GraphicsMode DescribePixelFormatPFD(IntPtr device, ref PixelFormatDescriptor pfd, + int pixelformat) { GraphicsMode created_mode = null; if (Functions.DescribePixelFormat(device, pixelformat, pfd.Size, ref pfd) > 0) @@ -345,7 +368,7 @@ namespace OpenTK.Platform.Windows } // Skip formats that don't offer full hardware acceleration - WGL_ARB_pixel_format acceleration = (WGL_ARB_pixel_format)attribs[0]; + WGL_ARB_pixel_format acceleration = (WGL_ARB_pixel_format)values[0]; if (acceleration == WGL_ARB_pixel_format.FullAccelerationArb) { // Construct a new GraphicsMode to describe this format From 0a46e20029ee70d75d0008c1709fd52d3fcf56d5 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 10:35:05 +0100 Subject: [PATCH 6/7] Added WGL_DRAW_TO_WINDOW_ARB flag Without this flag, OpenGL rendering does not work as expected. Additionally, all WGL_ARB_pixel_format attributes are expected to be specified in key-value pairs. Fixed double-buffering and stereoscoping rendering attributes. --- Source/OpenTK/Platform/Windows/WinGraphicsMode.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index a9544f71..9de28341 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -104,6 +104,9 @@ namespace OpenTK.Platform.Windows List attributes = new List(); attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb); attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb); + + attributes.Add((int)WGL_ARB_pixel_format.DrawToWindowArb); + attributes.Add(1); if (mode.ColorFormat.Red > 0) { @@ -176,11 +179,13 @@ namespace OpenTK.Platform.Windows if (mode.Buffers > 0) { attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb); + attributes.Add(mode.Buffers > 1 ? 1 : 0); } if (mode.Stereo) { attributes.Add((int)WGL_ARB_pixel_format.StereoArb); + attributes.Add(1); } attributes.Add(0); From 30cd9cb7f84afd2ccc3a437b2de299788ba15ec0 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 11:10:05 +0100 Subject: [PATCH 7/7] Fixed crash in MakeCurrent(null) MakeCurrent(null) should set the bound device context to zero. --- Source/OpenTK/Platform/Windows/WinGLContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGLContext.cs b/Source/OpenTK/Platform/Windows/WinGLContext.cs index 0e727df7..837c3e76 100644 --- a/Source/OpenTK/Platform/Windows/WinGLContext.cs +++ b/Source/OpenTK/Platform/Windows/WinGLContext.cs @@ -279,14 +279,14 @@ namespace OpenTK.Platform.Windows throw new ArgumentException("window", "Must point to a valid window."); success = Wgl.MakeCurrent(wnd.DeviceContext, Handle.Handle); + device_context = wnd.DeviceContext; } else { success = Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero); + device_context = IntPtr.Zero; } - device_context = wnd.DeviceContext; - if (!success) { throw new GraphicsContextException(String.Format(