Opentk/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs
Stefanos A 95316829ec Updated WGL init sequence
WinGraphicsMode no longer creates a temporary context in order to create
the list of available modes. Instead, it requires to be passed an
existing context in its constructor.

WinGLContext now creates one temporary context in its static constructor
and hands that to WinGraphicsMode.

WinFactory no longer supports the CreateGraphicsMode API. This API will
be removed in the future, because the link because contexts and modes
cannot be separated in the general case.
2013-11-09 15:07:19 +01:00

279 lines
11 KiB
C#

#region License
//
// The Open Toolkit Library License
//
// 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
// 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.
//
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using OpenTK.Graphics;
namespace OpenTK.Platform.Windows
{
class WinGraphicsMode : IGraphicsMode
{
#region Fields
readonly List<GraphicsMode> modes = new List<GraphicsMode>();
static readonly object SyncRoot = new object();
#endregion
#region Constructors
public WinGraphicsMode(ContextHandle context, IntPtr device)
{
lock (SyncRoot)
{
modes.AddRange(GetModesARB(context, device));
if (modes.Count == 0)
modes.AddRange(GetModesPFD(context, 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());
}
}
#endregion
#region IGraphicsMode Members
public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, int samples,
ColorFormat accum, int buffers, bool stereo)
{
GraphicsMode mode = null;
do
{
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));
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.
}
#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);
}
}
}
#endregion
#region GetModesPFD
IEnumerable<GraphicsMode> GetModesPFD(ContextHandle context, IntPtr device)
{
Debug.WriteLine(String.Format("Device context: {0}", device));
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;
// Make sure we don't turn off Aero on Vista and newer.
if (Environment.OSVersion.Version.Major >= 6)
{
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.
int pixel = 0;
while (DescribePixelFormat(device, ++pixel, API.PixelFormatDescriptorSize, ref pfd) != 0)
{
// 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;
}
}
}
#endregion
#region GetModesARB
IEnumerable<GraphicsMode> GetModesARB(ContextHandle context, IntPtr device)
{
// 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)
{
Debug.WriteLine("failed.");
yield break;
}
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
};
int[] values = new int[attribs.Length];
int[] attribs_values = new int[]
{
(int)WGL_ARB_pixel_format.AccelerationArb,
(int)WGL_ARB_pixel_format.FullAccelerationArb,
(int)WGL_ARB_pixel_format.SupportOpenglArb, 1,
(int)WGL_ARB_pixel_format.DrawToWindowArb, 1,
0, 0
};
int[] num_formats = new int[1];
// Get the number of available formats
if (Wgl.Arb.ChoosePixelFormat(device, attribs_values, null, 0, null, num_formats))
{
// Create an array big enough to hold all available formats and get those formats
int[] pixel = new int[num_formats[0]];
if (Wgl.Arb.ChoosePixelFormat(device, attribs_values, null, pixel.Length, pixel, num_formats))
{
foreach (int p in pixel)
{
// Find out what we really got as a 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;
}
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;
}
}
}
}
#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
}
}