PageRenderTime 34ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/GoliatEditor/OpenTK/1.1/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs

https://gitlab.com/gonzague.defraiteur/GoliatEditor
C# | 429 lines | 308 code | 61 blank | 60 comment | 54 complexity | a6027243a9aa88dccba0c9487d314b5a MD5 | raw file
  1. #region License
  2. //
  3. // The Open Toolkit Library License
  4. //
  5. // Copyright (c) 2006 - 2010 the Open Toolkit library.
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights to
  10. // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  11. // the Software, and to permit persons to whom the Software is furnished to do
  12. // so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in all
  15. // copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  19. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  24. // OTHER DEALINGS IN THE SOFTWARE.
  25. //
  26. #endregion
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Text;
  30. using System.Diagnostics;
  31. using System.Runtime.InteropServices;
  32. using OpenTK.Graphics;
  33. namespace OpenTK.Platform.Windows
  34. {
  35. class WinGraphicsMode : IGraphicsMode
  36. {
  37. enum AccelerationType
  38. {
  39. // Software acceleration
  40. None = 0,
  41. // Partial acceleration (Direct3D emulation)
  42. MCD,
  43. // Full acceleration
  44. ICD,
  45. }
  46. readonly IntPtr Device;
  47. #region Constructors
  48. public WinGraphicsMode(IntPtr device)
  49. {
  50. if (device == IntPtr.Zero)
  51. throw new ArgumentException();
  52. Device = device;
  53. }
  54. #endregion
  55. #region IGraphicsMode Members
  56. public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, int samples,
  57. ColorFormat accum, int buffers, bool stereo)
  58. {
  59. GraphicsMode mode = new GraphicsMode(color, depth, stencil, samples,accum, buffers, stereo);
  60. GraphicsMode created_mode = ChoosePixelFormatARB(Device, mode);
  61. // If ChoosePixelFormatARB failed, iterate through all acceleration types in turn (ICD, MCD, None)
  62. // This should fix issue #2224, which causes OpenTK to fail on VMs without hardware acceleration.
  63. created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.ICD);
  64. created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.MCD);
  65. created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.None);
  66. if (created_mode == null)
  67. {
  68. throw new GraphicsModeException("The requested GraphicsMode is not supported");
  69. }
  70. return created_mode;
  71. }
  72. #endregion
  73. #region Private Methods
  74. #region ChoosePixelFormatARB
  75. // Queries pixel formats through the WGL_ARB_pixel_format extension
  76. // This method only returns accelerated formats. If no format offers
  77. // hardware acceleration (e.g. we are running in a VM or in a remote desktop
  78. // connection), this method will return 0 formats and we will fall back to
  79. // ChoosePixelFormatPFD.
  80. GraphicsMode ChoosePixelFormatARB(IntPtr device, GraphicsMode desired_mode)
  81. {
  82. GraphicsMode created_mode = null;
  83. GraphicsMode mode = new GraphicsMode(desired_mode);
  84. if (Wgl.SupportsExtension("WGL_ARB_pixel_format") &&
  85. Wgl.SupportsFunction("wglChoosePixelFormatARB"))
  86. {
  87. int[] format = new int[1];
  88. int count;
  89. List<int> attributes = new List<int>();
  90. bool retry = false;
  91. do
  92. {
  93. attributes.Clear();
  94. attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb);
  95. attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb);
  96. attributes.Add((int)WGL_ARB_pixel_format.DrawToWindowArb);
  97. attributes.Add(1);
  98. if (mode.ColorFormat.Red > 0)
  99. {
  100. attributes.Add((int)WGL_ARB_pixel_format.RedBitsArb);
  101. attributes.Add(mode.ColorFormat.Red);
  102. }
  103. if (mode.ColorFormat.Green > 0)
  104. {
  105. attributes.Add((int)WGL_ARB_pixel_format.GreenBitsArb);
  106. attributes.Add(mode.ColorFormat.Green);
  107. }
  108. if (mode.ColorFormat.Blue > 0)
  109. {
  110. attributes.Add((int)WGL_ARB_pixel_format.BlueBitsArb);
  111. attributes.Add(mode.ColorFormat.Blue);
  112. }
  113. if (mode.ColorFormat.Alpha > 0)
  114. {
  115. attributes.Add((int)WGL_ARB_pixel_format.AlphaBitsArb);
  116. attributes.Add(mode.ColorFormat.Alpha);
  117. }
  118. if (mode.Depth > 0)
  119. {
  120. attributes.Add((int)WGL_ARB_pixel_format.DepthBitsArb);
  121. attributes.Add(mode.Depth);
  122. }
  123. if (mode.Stencil > 0)
  124. {
  125. attributes.Add((int)WGL_ARB_pixel_format.StencilBitsArb);
  126. attributes.Add(mode.Stencil);
  127. }
  128. if (mode.AccumulatorFormat.Red > 0)
  129. {
  130. attributes.Add((int)WGL_ARB_pixel_format.AccumRedBitsArb);
  131. attributes.Add(mode.AccumulatorFormat.Red);
  132. }
  133. if (mode.AccumulatorFormat.Green > 0)
  134. {
  135. attributes.Add((int)WGL_ARB_pixel_format.AccumGreenBitsArb);
  136. attributes.Add(mode.AccumulatorFormat.Green);
  137. }
  138. if (mode.AccumulatorFormat.Blue > 0)
  139. {
  140. attributes.Add((int)WGL_ARB_pixel_format.AccumBlueBitsArb);
  141. attributes.Add(mode.AccumulatorFormat.Blue);
  142. }
  143. if (mode.AccumulatorFormat.Alpha > 0)
  144. {
  145. attributes.Add((int)WGL_ARB_pixel_format.AccumAlphaBitsArb);
  146. attributes.Add(mode.AccumulatorFormat.Alpha);
  147. }
  148. if (mode.Samples > 0 &&
  149. Wgl.SupportsExtension("WGL_ARB_multisample"))
  150. {
  151. attributes.Add((int)WGL_ARB_multisample.SampleBuffersArb);
  152. attributes.Add(1);
  153. attributes.Add((int)WGL_ARB_multisample.SamplesArb);
  154. attributes.Add(mode.Samples);
  155. }
  156. if (mode.Buffers > 0)
  157. {
  158. attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb);
  159. attributes.Add(mode.Buffers > 1 ? 1 : 0);
  160. }
  161. if (mode.Stereo)
  162. {
  163. attributes.Add((int)WGL_ARB_pixel_format.StereoArb);
  164. attributes.Add(1);
  165. }
  166. attributes.Add(0);
  167. attributes.Add(0);
  168. if (Wgl.Arb.ChoosePixelFormat(device, attributes.ToArray(), null, format.Length, format, out count)
  169. && count > 0)
  170. {
  171. created_mode = DescribePixelFormatARB(device, format[0]);
  172. retry = false;
  173. }
  174. else
  175. {
  176. Debug.Print("[WGL] ChoosePixelFormatARB failed with {0}", Marshal.GetLastWin32Error());
  177. retry = Utilities.RelaxGraphicsMode(ref mode);
  178. }
  179. }
  180. while (retry);
  181. }
  182. else
  183. {
  184. Debug.WriteLine("[WGL] ChoosePixelFormatARB not supported on this context");
  185. }
  186. return created_mode;
  187. }
  188. #endregion
  189. #region ChoosePixelFormatPFD
  190. static bool Compare(int got, int requested, ref int distance)
  191. {
  192. bool valid = true;
  193. if (got == 0 && requested != 0)
  194. {
  195. // mode does not support the requested feature.
  196. valid = false;
  197. }
  198. else if (got >= requested)
  199. {
  200. // mode supports the requested feature,
  201. // calculate the distance from an "ideal" mode
  202. // that matches this feature exactly.
  203. distance += got - requested;
  204. }
  205. else
  206. {
  207. // mode supports the requested feature,
  208. // but at a suboptimal level. For example:
  209. // - requsted AA = 8x, got 4x
  210. // - requested color = 32bpp, got 16bpp
  211. // We can still use this mode but only if
  212. // no better mode exists.
  213. const int penalty = 8;
  214. distance += penalty * Math.Abs(got - requested);
  215. }
  216. return valid;
  217. }
  218. static AccelerationType GetAccelerationType(ref PixelFormatDescriptor pfd)
  219. {
  220. AccelerationType type = AccelerationType.ICD;
  221. if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0)
  222. {
  223. if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_ACCELERATED) != 0)
  224. {
  225. type = AccelerationType.MCD;
  226. }
  227. else
  228. {
  229. type = AccelerationType.None;
  230. }
  231. }
  232. return type;
  233. }
  234. GraphicsMode ChoosePixelFormatPFD(IntPtr device, GraphicsMode mode, AccelerationType requested_acceleration_type)
  235. {
  236. PixelFormatDescriptor pfd = new PixelFormatDescriptor();
  237. PixelFormatDescriptorFlags flags = 0;
  238. flags |= PixelFormatDescriptorFlags.DRAW_TO_WINDOW;
  239. flags |= PixelFormatDescriptorFlags.SUPPORT_OPENGL;
  240. if (mode.Stereo)
  241. {
  242. flags |= PixelFormatDescriptorFlags.STEREO;
  243. }
  244. if (System.Environment.OSVersion.Version.Major >= 6 &&
  245. requested_acceleration_type != AccelerationType.None)
  246. {
  247. // Request a compositor-capable mode when running on
  248. // Vista+ and using hardware acceleration. Without this,
  249. // some modes will cause the compositor to turn off,
  250. // which is very annoying to the user.
  251. // Note: compositor-capable modes require hardware
  252. // acceleration. Don't set this flag when running
  253. // with software acceleration (e.g. over Remote Desktop
  254. // as described in bug https://github.com/opentk/opentk/issues/35)
  255. flags |= PixelFormatDescriptorFlags.SUPPORT_COMPOSITION;
  256. }
  257. int count = Functions.DescribePixelFormat(device, 1, API.PixelFormatDescriptorSize, ref pfd);
  258. int best = 0;
  259. int best_dist = int.MaxValue;
  260. for (int index = 1; index <= count; index++)
  261. {
  262. int dist = 0;
  263. bool valid = Functions.DescribePixelFormat(device, index, API.PixelFormatDescriptorSize, ref pfd) != 0;
  264. valid &= GetAccelerationType(ref pfd) == requested_acceleration_type;
  265. valid &= (pfd.Flags & flags) == flags;
  266. valid &= pfd.PixelType == PixelType.RGBA; // indexed modes not currently supported
  267. // heavily penalize single-buffered modes when the user requests double buffering
  268. if ((pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) == 0 && mode.Buffers > 1)
  269. dist += 1000;
  270. valid &= Compare(pfd.ColorBits, mode.ColorFormat.BitsPerPixel, ref dist);
  271. valid &= Compare(pfd.RedBits, mode.ColorFormat.Red, ref dist);
  272. valid &= Compare(pfd.GreenBits, mode.ColorFormat.Green, ref dist);
  273. valid &= Compare(pfd.BlueBits, mode.ColorFormat.Blue, ref dist);
  274. valid &= Compare(pfd.AlphaBits, mode.ColorFormat.Alpha, ref dist);
  275. valid &= Compare(pfd.AccumBits, mode.AccumulatorFormat.BitsPerPixel, ref dist);
  276. valid &= Compare(pfd.AccumRedBits, mode.AccumulatorFormat.Red, ref dist);
  277. valid &= Compare(pfd.AccumGreenBits, mode.AccumulatorFormat.Green, ref dist);
  278. valid &= Compare(pfd.AccumBlueBits, mode.AccumulatorFormat.Blue, ref dist);
  279. valid &= Compare(pfd.AccumAlphaBits, mode.AccumulatorFormat.Alpha, ref dist);
  280. valid &= Compare(pfd.DepthBits, mode.Depth, ref dist);
  281. valid &= Compare(pfd.StencilBits, mode.Stencil, ref dist);
  282. if (valid && dist < best_dist)
  283. {
  284. best = index;
  285. best_dist = dist;
  286. }
  287. }
  288. return DescribePixelFormatPFD(device, ref pfd, best);
  289. }
  290. #endregion
  291. #region DescribePixelFormatPFD
  292. static GraphicsMode DescribePixelFormatPFD(IntPtr device, ref PixelFormatDescriptor pfd,
  293. int pixelformat)
  294. {
  295. GraphicsMode created_mode = null;
  296. if (Functions.DescribePixelFormat(device, pixelformat, pfd.Size, ref pfd) > 0)
  297. {
  298. created_mode = new GraphicsMode(
  299. new IntPtr(pixelformat),
  300. new ColorFormat(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits),
  301. pfd.DepthBits,
  302. pfd.StencilBits,
  303. 0, // MSAA not supported when using PixelFormatDescriptor
  304. new ColorFormat(pfd.AccumRedBits, pfd.AccumGreenBits, pfd.AccumBlueBits, pfd.AccumAlphaBits),
  305. (pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) != 0 ? 2 : 1,
  306. (pfd.Flags & PixelFormatDescriptorFlags.STEREO) != 0);
  307. }
  308. return created_mode;
  309. }
  310. #endregion
  311. #region DescribePixelFormatARB
  312. GraphicsMode DescribePixelFormatARB(IntPtr device, int pixelformat)
  313. {
  314. GraphicsMode created_mode = null;
  315. // See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt for more details
  316. if (Wgl.SupportsFunction("wglGetPixelFormatAttribivARB"))
  317. {
  318. // Define the list of attributes we are interested in.
  319. // The results will be stored in the 'values' array below.
  320. int[] attribs = new int[]
  321. {
  322. (int)WGL_ARB_pixel_format.AccelerationArb,
  323. (int)WGL_ARB_pixel_format.RedBitsArb,
  324. (int)WGL_ARB_pixel_format.GreenBitsArb,
  325. (int)WGL_ARB_pixel_format.BlueBitsArb,
  326. (int)WGL_ARB_pixel_format.AlphaBitsArb,
  327. (int)WGL_ARB_pixel_format.ColorBitsArb,
  328. (int)WGL_ARB_pixel_format.DepthBitsArb,
  329. (int)WGL_ARB_pixel_format.StencilBitsArb,
  330. (int)WGL_ARB_multisample.SampleBuffersArb,
  331. (int)WGL_ARB_multisample.SamplesArb,
  332. (int)WGL_ARB_pixel_format.AccumRedBitsArb,
  333. (int)WGL_ARB_pixel_format.AccumGreenBitsArb,
  334. (int)WGL_ARB_pixel_format.AccumBlueBitsArb,
  335. (int)WGL_ARB_pixel_format.AccumAlphaBitsArb,
  336. (int)WGL_ARB_pixel_format.AccumBitsArb,
  337. (int)WGL_ARB_pixel_format.DoubleBufferArb,
  338. (int)WGL_ARB_pixel_format.StereoArb,
  339. 0
  340. };
  341. // Allocate storage for the results of GetPixelFormatAttrib queries
  342. int[] values = new int[attribs.Length];
  343. // Get the format attributes for this pixel format
  344. if (!Wgl.Arb.GetPixelFormatAttrib(device, pixelformat, 0, attribs.Length - 1, attribs, values))
  345. {
  346. Debug.Print("[Warning] Failed to detect attributes for PixelFormat: {0}.", pixelformat);
  347. }
  348. // Skip formats that don't offer full hardware acceleration
  349. WGL_ARB_pixel_format acceleration = (WGL_ARB_pixel_format)values[0];
  350. if (acceleration == WGL_ARB_pixel_format.FullAccelerationArb)
  351. {
  352. // Construct a new GraphicsMode to describe this format
  353. created_mode = new GraphicsMode(new IntPtr(pixelformat),
  354. new ColorFormat(values[1], values[2], values[3], values[4]),
  355. values[6],
  356. values[7],
  357. values[8] != 0 ? values[9] : 0,
  358. new ColorFormat(values[10], values[11], values[12], values[13]),
  359. values[15] == 1 ? 2 : 1,
  360. values[16] == 1 ? true : false);
  361. }
  362. }
  363. return created_mode;
  364. }
  365. #endregion
  366. #endregion
  367. }
  368. }