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.
This commit is contained in:
Stefanos A 2013-12-22 09:20:40 +01:00
parent dfd90c8a43
commit dec02d5534

View file

@ -105,18 +105,28 @@ namespace OpenTK.Platform.Windows
attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb); attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb);
attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb); 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((int)WGL_ARB_pixel_format.RedBitsArb);
attributes.Add(mode.ColorFormat.Red); attributes.Add(mode.ColorFormat.Red);
}
if (mode.ColorFormat.Green > 0)
{
attributes.Add((int)WGL_ARB_pixel_format.GreenBitsArb); attributes.Add((int)WGL_ARB_pixel_format.GreenBitsArb);
attributes.Add(mode.ColorFormat.Green); attributes.Add(mode.ColorFormat.Green);
}
if (mode.ColorFormat.Blue > 0)
{
attributes.Add((int)WGL_ARB_pixel_format.BlueBitsArb); attributes.Add((int)WGL_ARB_pixel_format.BlueBitsArb);
attributes.Add(mode.ColorFormat.Blue); attributes.Add(mode.ColorFormat.Blue);
}
if (mode.ColorFormat.Alpha > 0)
{
attributes.Add((int)WGL_ARB_pixel_format.AlphaBitsArb); attributes.Add((int)WGL_ARB_pixel_format.AlphaBitsArb);
attributes.Add(mode.ColorFormat.Alpha); attributes.Add(mode.ColorFormat.Alpha);
attributes.Add((int)WGL_ARB_pixel_format.ColorBitsArb);
attributes.Add(mode.ColorFormat.BitsPerPixel);
} }
if (mode.Depth > 0) if (mode.Depth > 0)
@ -131,18 +141,28 @@ namespace OpenTK.Platform.Windows
attributes.Add(mode.Stencil); attributes.Add(mode.Stencil);
} }
if (mode.AccumulatorFormat.BitsPerPixel > 0) if (mode.AccumulatorFormat.Red > 0)
{ {
attributes.Add((int)WGL_ARB_pixel_format.AccumRedBitsArb); attributes.Add((int)WGL_ARB_pixel_format.AccumRedBitsArb);
attributes.Add(mode.AccumulatorFormat.Red); attributes.Add(mode.AccumulatorFormat.Red);
}
if (mode.AccumulatorFormat.Green > 0)
{
attributes.Add((int)WGL_ARB_pixel_format.AccumGreenBitsArb); attributes.Add((int)WGL_ARB_pixel_format.AccumGreenBitsArb);
attributes.Add(mode.AccumulatorFormat.Green); attributes.Add(mode.AccumulatorFormat.Green);
}
if (mode.AccumulatorFormat.Blue > 0)
{
attributes.Add((int)WGL_ARB_pixel_format.AccumBlueBitsArb); attributes.Add((int)WGL_ARB_pixel_format.AccumBlueBitsArb);
attributes.Add(mode.AccumulatorFormat.Blue); attributes.Add(mode.AccumulatorFormat.Blue);
}
if (mode.AccumulatorFormat.Alpha > 0)
{
attributes.Add((int)WGL_ARB_pixel_format.AccumAlphaBitsArb); attributes.Add((int)WGL_ARB_pixel_format.AccumAlphaBitsArb);
attributes.Add(mode.AccumulatorFormat.Alpha); attributes.Add(mode.AccumulatorFormat.Alpha);
attributes.Add((int)WGL_ARB_pixel_format.AccumBitsArb);
attributes.Add(mode.AccumulatorFormat.BitsPerPixel);
} }
if (mode.Samples > 0) if (mode.Samples > 0)
@ -156,13 +176,11 @@ namespace OpenTK.Platform.Windows
if (mode.Buffers > 0) if (mode.Buffers > 0)
{ {
attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb); attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb);
attributes.Add(mode.Buffers);
} }
if (mode.Stereo) if (mode.Stereo)
{ {
attributes.Add((int)WGL_ARB_pixel_format.StereoArb); attributes.Add((int)WGL_ARB_pixel_format.StereoArb);
attributes.Add(1);
} }
attributes.Add(0); attributes.Add(0);
@ -181,7 +199,7 @@ namespace OpenTK.Platform.Windows
} }
else else
{ {
Debug.Print("[WGL] ChoosePixelFormatARB not supported"); Debug.WriteLine("[WGL] ChoosePixelFormatARB not supported on this context");
} }
return created_mode; return created_mode;
@ -191,94 +209,99 @@ namespace OpenTK.Platform.Windows
#region ChoosePixelFormatPFD #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(); if (got < requested)
pfd.Size = (short)BlittableValueType<PixelFormatDescriptor>.Stride;
if (mode.ColorFormat.BitsPerPixel > 0)
{ {
pfd.RedBits = (byte)mode.ColorFormat.Red; return false;
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;
} }
else else
{ {
pfd.Flags |= PixelFormatDescriptorFlags.DEPTH_DONTCARE; distance += got - requested;
return true;
}
} }
if (mode.Stencil > 0) static AccelerationType GetAccelerationType(ref PixelFormatDescriptor pfd)
{ {
pfd.StencilBits = (byte)mode.Stencil; AccelerationType type = AccelerationType.ICD;
}
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;
}
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)
{
pfd.Flags |= PixelFormatDescriptorFlags.SUPPORT_COMPOSITION;
}
GraphicsMode created_mode = null;
int pixelformat = Functions.ChoosePixelFormat(device, ref pfd);
if (pixelformat > 0)
{
AccelerationType acceleration_type = AccelerationType.ICD;
if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0)
{ {
if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_ACCELERATED) != 0) if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_ACCELERATED) != 0)
{ {
acceleration_type = AccelerationType.MCD; type = AccelerationType.MCD;
} }
else else
{ {
acceleration_type = AccelerationType.None; type = AccelerationType.None;
}
}
return type;
}
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)
{
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;
}
int count = Functions.DescribePixelFormat(device, 1, API.PixelFormatDescriptorSize, ref pfd);
int best = 0;
int best_dist = int.MaxValue;
for (int index = 1; index <= count; index++)
{
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 (valid && dist < best_dist)
{
best = index;
best_dist = dist;
} }
} }
if (acceleration_type == requested_acceleration_type) return DescribePixelFormatPFD(device, ref pfd, best);
{
created_mode = DescribePixelFormatPFD(device, ref pfd, pixelformat);
}
}
return created_mode;
} }
#endregion #endregion
#region DescribePixelFormatPFD #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; GraphicsMode created_mode = null;
if (Functions.DescribePixelFormat(device, pixelformat, pfd.Size, ref pfd) > 0) 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 // 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) if (acceleration == WGL_ARB_pixel_format.FullAccelerationArb)
{ {
// Construct a new GraphicsMode to describe this format // Construct a new GraphicsMode to describe this format