2010-10-02 18:52:34 +00:00
|
|
|
#region License
|
2009-06-01 11:05:31 +00:00
|
|
|
//
|
|
|
|
// The Open Toolkit Library License
|
|
|
|
//
|
2010-11-08 19:41:24 +00:00
|
|
|
// Copyright (c) 2006 - 2010 the Open Toolkit library.
|
2009-06-01 11:05:31 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2009-02-22 10:43:35 +00:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Text;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
|
|
|
using OpenTK.Graphics;
|
|
|
|
|
|
|
|
namespace OpenTK.Platform.Windows
|
|
|
|
{
|
2010-11-11 19:32:22 +00:00
|
|
|
class WinGraphicsMode : IGraphicsMode
|
2009-02-22 10:43:35 +00:00
|
|
|
{
|
2010-11-08 19:41:24 +00:00
|
|
|
#region Fields
|
2009-06-01 11:05:31 +00:00
|
|
|
|
2010-11-08 19:41:24 +00:00
|
|
|
readonly List<GraphicsMode> modes = new List<GraphicsMode>();
|
2010-11-08 16:01:50 +00:00
|
|
|
static readonly object SyncRoot = new object();
|
2009-06-01 11:05:31 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
2010-11-21 20:16:18 +00:00
|
|
|
#region Constructors
|
2009-02-22 10:43:35 +00:00
|
|
|
|
2013-11-14 07:05:08 +00:00
|
|
|
public WinGraphicsMode(IntPtr device)
|
2009-02-22 10:43:35 +00:00
|
|
|
{
|
2010-11-08 19:41:24 +00:00
|
|
|
lock (SyncRoot)
|
|
|
|
{
|
2013-11-14 07:05:08 +00:00
|
|
|
modes.AddRange(GetModesARB(device));
|
2013-11-08 09:46:27 +00:00
|
|
|
if (modes.Count == 0)
|
2013-11-14 07:05:08 +00:00
|
|
|
modes.AddRange(GetModesPFD(device));
|
2013-11-08 09:46:27 +00:00
|
|
|
if (modes.Count == 0)
|
|
|
|
throw new GraphicsModeException(
|
|
|
|
"No GraphicsMode available. This should never happen, please report a bug at http://www.opentk.com");
|
2010-11-08 19:41:24 +00:00
|
|
|
modes.Sort(new GraphicsModeComparer());
|
|
|
|
}
|
2009-02-22 10:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
2010-11-08 19:41:24 +00:00
|
|
|
#region IGraphicsMode Members
|
2009-02-22 10:43:35 +00:00
|
|
|
|
2010-11-08 19:41:24 +00:00
|
|
|
public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, int samples,
|
|
|
|
ColorFormat accum, int buffers, bool stereo)
|
2009-02-22 10:43:35 +00:00
|
|
|
{
|
2010-11-08 19:41:24 +00:00
|
|
|
GraphicsMode mode = null;
|
|
|
|
do
|
2009-06-01 11:05:31 +00:00
|
|
|
{
|
2010-11-08 19:41:24 +00:00
|
|
|
mode = modes.Find(delegate(GraphicsMode current)
|
2009-06-01 11:05:31 +00:00
|
|
|
{
|
2010-11-08 19:41:24 +00:00
|
|
|
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));
|
2010-11-08 16:01:50 +00:00
|
|
|
|
2010-11-11 19:32:22 +00:00
|
|
|
if (mode == null)
|
|
|
|
mode = modes[0];
|
|
|
|
|
2010-11-08 19:41:24 +00:00
|
|
|
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; }
|
2010-11-11 19:32:22 +00:00
|
|
|
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; }
|
2010-11-08 19:41:24 +00:00
|
|
|
if (color < 16) { color = 16; return true; }
|
2010-11-11 19:32:22 +00:00
|
|
|
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.
|
2009-02-22 10:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
2010-11-08 19:41:24 +00:00
|
|
|
#region Private Methods
|
2009-02-22 10:43:35 +00:00
|
|
|
|
2010-11-08 19:41:24 +00:00
|
|
|
#region GetModesPFD
|
2009-02-22 10:43:35 +00:00
|
|
|
|
2013-11-14 07:05:08 +00:00
|
|
|
IEnumerable<GraphicsMode> GetModesPFD(IntPtr device)
|
2010-11-08 19:41:24 +00:00
|
|
|
{
|
2013-11-08 09:46:27 +00:00
|
|
|
Debug.WriteLine(String.Format("Device context: {0}", device));
|
2010-11-08 19:41:24 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2011-02-09 00:23:43 +00:00
|
|
|
// Make sure we don't turn off Aero on Vista and newer.
|
|
|
|
if (Environment.OSVersion.Version.Major >= 6)
|
2010-11-08 19:41:24 +00:00
|
|
|
{
|
2011-02-09 00:23:43 +00:00
|
|
|
pfd.Flags |= PixelFormatDescriptorFlags.SUPPORT_COMPOSITION;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (bool generic_allowed in new bool[] { false, true })
|
|
|
|
{
|
|
|
|
// 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.
|
2013-12-17 15:40:15 +00:00
|
|
|
// Note: DescribePixelFormat found in gdi32 is extremely slow on nvidia, for some reason.
|
2011-02-09 00:23:43 +00:00
|
|
|
int pixel = 0;
|
2013-12-17 21:35:30 +00:00
|
|
|
while (Functions.DescribePixelFormat(device, ++pixel, API.PixelFormatDescriptorSize, ref pfd) != 0)
|
2011-02-09 00:23:43 +00:00
|
|
|
{
|
|
|
|
// Ignore non-accelerated formats.
|
|
|
|
if (!generic_allowed && (pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2009-02-22 10:43:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
2010-11-08 19:41:24 +00:00
|
|
|
#region GetModesARB
|
2009-02-22 10:43:35 +00:00
|
|
|
|
2013-12-18 13:16:49 +00:00
|
|
|
// 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.
|
2013-11-14 07:05:08 +00:00
|
|
|
IEnumerable<GraphicsMode> GetModesARB(IntPtr device)
|
2009-02-22 10:43:35 +00:00
|
|
|
{
|
2013-11-08 09:46:27 +00:00
|
|
|
// 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)
|
2009-06-01 11:05:31 +00:00
|
|
|
{
|
2013-11-08 09:46:27 +00:00
|
|
|
Debug.WriteLine("failed.");
|
|
|
|
yield break;
|
|
|
|
}
|
2009-06-01 11:05:31 +00:00
|
|
|
|
2013-12-18 13:16:49 +00:00
|
|
|
// 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.
|
2013-11-08 09:46:27 +00:00
|
|
|
int[] attribs = new int[]
|
|
|
|
{
|
|
|
|
(int)WGL_ARB_pixel_format.AccelerationArb,
|
2009-06-01 11:05:31 +00:00
|
|
|
|
2013-11-08 09:46:27 +00:00
|
|
|
(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,
|
2009-06-01 11:05:31 +00:00
|
|
|
|
2013-11-08 09:46:27 +00:00
|
|
|
(int)WGL_ARB_pixel_format.DepthBitsArb,
|
|
|
|
(int)WGL_ARB_pixel_format.StencilBitsArb,
|
2009-06-01 11:05:31 +00:00
|
|
|
|
2013-11-08 09:46:27 +00:00
|
|
|
(int)WGL_ARB_multisample.SampleBuffersArb,
|
|
|
|
(int)WGL_ARB_multisample.SamplesArb,
|
2009-06-01 11:05:31 +00:00
|
|
|
|
2013-11-08 09:46:27 +00:00
|
|
|
(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,
|
2009-06-01 11:05:31 +00:00
|
|
|
|
2013-11-08 09:46:27 +00:00
|
|
|
(int)WGL_ARB_pixel_format.DoubleBufferArb,
|
|
|
|
(int)WGL_ARB_pixel_format.StereoArb,
|
|
|
|
0
|
|
|
|
};
|
2009-06-01 11:05:31 +00:00
|
|
|
|
2013-12-18 13:16:49 +00:00
|
|
|
// Allocate storage for the results of GetPixelFormatAttrib queries
|
2013-11-08 09:46:27 +00:00
|
|
|
int[] values = new int[attribs.Length];
|
2009-06-01 11:05:31 +00:00
|
|
|
|
2013-11-08 09:46:27 +00:00
|
|
|
// Get the number of available formats
|
2013-12-18 13:16:49 +00:00
|
|
|
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))
|
2013-11-08 09:46:27 +00:00
|
|
|
{
|
2013-12-18 13:16:49 +00:00
|
|
|
for (int p = 1; p < num_formats; p++)
|
2010-10-02 18:52:34 +00:00
|
|
|
{
|
2013-12-18 13:16:49 +00:00
|
|
|
// Get the format attributes for this pixel format
|
|
|
|
if (!Wgl.Arb.GetPixelFormatAttrib(device, p, 0, attribs.Length - 1, attribs, values))
|
2010-11-08 19:41:24 +00:00
|
|
|
{
|
2013-12-18 13:16:49 +00:00
|
|
|
Debug.Print("[Warning] Failed to detect attributes for PixelFormat:{0}.", p);
|
|
|
|
continue;
|
2010-11-08 19:41:24 +00:00
|
|
|
}
|
2013-12-18 13:16:49 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct a new GraphicsMode to describe this format
|
|
|
|
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;
|
2010-10-02 18:52:34 +00:00
|
|
|
}
|
2009-06-01 11:05:31 +00:00
|
|
|
}
|
2009-02-22 10:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
2010-11-08 19:41:24 +00:00
|
|
|
#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
|
|
|
|
|
2009-02-22 10:43:35 +00:00
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|