mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-24 17:45:37 +00:00
Retrieve all pixel formats at once and select the correct one through a custom selection predicate. Simplifies the code significantly and reduces the chance of race conditions.
This commit is contained in:
parent
d08438785e
commit
fd3e1850b7
|
@ -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<GraphicsMode> modes = new List<GraphicsMode>();
|
||||
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<GraphicsMode> 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<GraphicsMode> 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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue