Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
GraphicsDeviceManager.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 //
4 // Copyright (c) 2010-2013 SharpDX - Alexandre Mutel
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 
24 using System;
25 using System.Collections.Generic;
26 using SiliconStudio.Core.Diagnostics;
27 using SiliconStudio.Paradox.Graphics;
28 using SiliconStudio.Core;
29 
30 namespace SiliconStudio.Paradox.Games
31 {
32  /// <summary>
33  /// Manages the <see cref="GraphicsDevice"/> lifecycle.
34  /// </summary>
36  {
37  #region Fields
38 
39  /// <summary>
40  /// Default width for the back buffer.
41  /// </summary>
42  public static readonly int DefaultBackBufferWidth = 1280;
43 
44  /// <summary>
45  /// Default height for the back buffer.
46  /// </summary>
47  public static readonly int DefaultBackBufferHeight = 720;
48 
49  private GameBase game;
50 
51  private bool deviceSettingsChanged;
52 
53  private bool isFullScreen;
54 
55  private bool preferMultiSampling;
56 
57  private PixelFormat preferredBackBufferFormat;
58 
59  private int preferredBackBufferHeight;
60 
61  private int preferredBackBufferWidth;
62 
63  private Rational preferredRefreshRate;
64 
65  private PixelFormat preferredDepthStencilFormat;
66 
67  private DisplayOrientation supportedOrientations;
68 
69  private bool synchronizeWithVerticalRetrace;
70 
71  private int preferredFullScreenOutputIndex;
72 
73  private bool isChangingDevice;
74 
75  private int resizedBackBufferWidth;
76 
77  private int resizedBackBufferHeight;
78 
79  private bool isBackBufferToResize = false;
80 
81  private DisplayOrientation currentWindowOrientation;
82 
83  private bool beginDrawOk;
84 
85  private IGraphicsDeviceFactory graphicsDeviceFactory;
86 
87  private bool isReallyFullScreen;
88 
89  #endregion
90 
91  #region Constructors and Destructors
92 
93  /// <summary>
94  /// Initializes a new instance of the <see cref="GraphicsDeviceManager" /> class.
95  /// </summary>
96  /// <param name="game">The game.</param>
97  /// <exception cref="System.ArgumentNullException">The game instance cannot be null.</exception>
98  internal GraphicsDeviceManager(GameBase game)
99  {
100  this.game = game;
101  if (this.game == null)
102  {
103  throw new ArgumentNullException("game");
104  }
105 
106  // Defines all default values
107  SynchronizeWithVerticalRetrace = true;
108  PreferredBackBufferFormat = PixelFormat.R8G8B8A8_UNorm;;
109  PreferredDepthStencilFormat = PixelFormat.D24_UNorm_S8_UInt;
110  preferredBackBufferWidth = DefaultBackBufferWidth;
111  preferredBackBufferHeight = DefaultBackBufferHeight;
112  preferredRefreshRate = new Rational(60, 1);
113  PreferMultiSampling = false;
114  PreferredGraphicsProfile = new[]
115  {
116 #if SILICONSTUDIO_PLATFORM_WINDOWS_PHONE
117  GraphicsProfile.Level_9_3,
118 #else
119  GraphicsProfile.Level_11_1,
120  GraphicsProfile.Level_11_0,
121  GraphicsProfile.Level_10_1,
122  GraphicsProfile.Level_10_0,
123  GraphicsProfile.Level_9_3,
124  GraphicsProfile.Level_9_2,
125  GraphicsProfile.Level_9_1,
126 #endif
127  };
128 
129  // Register the services to the registry
130  game.Services.AddService(typeof(IGraphicsDeviceManager), this);
131  game.Services.AddService(typeof(IGraphicsDeviceService), this);
132 
133  graphicsDeviceFactory = (IGraphicsDeviceFactory)game.Services.GetService(typeof(IGraphicsDeviceFactory));
134  if (graphicsDeviceFactory == null)
135  {
136  throw new InvalidOperationException("IGraphicsDeviceFactory is not registered as a service");
137  }
138 
139  game.WindowCreated += GameOnWindowCreated;
140  }
141 
142  private void GameOnWindowCreated(object sender, EventArgs eventArgs)
143  {
144  game.Window.ClientSizeChanged += Window_ClientSizeChanged;
145  game.Window.OrientationChanged += Window_OrientationChanged;
146  }
147 
148  #endregion
149 
150  #region Public Events
151 
152  public event EventHandler<EventArgs> DeviceCreated;
153 
154  public event EventHandler<EventArgs> DeviceDisposing;
155 
156  public event EventHandler<EventArgs> DeviceReset;
157 
158  public event EventHandler<EventArgs> DeviceResetting;
159 
160  public event EventHandler<PreparingDeviceSettingsEventArgs> PreparingDeviceSettings;
161 
162  #endregion
163 
164  #region Public Properties
165 
166  public GraphicsDevice GraphicsDevice { get; internal set; }
167 
168  /// <summary>
169  /// Gets or sets the list of graphics profile to select from the best feature to the lower feature. See remarks.
170  /// </summary>
171  /// <value>The graphics profile.</value>
172  /// <remarks>
173  /// By default, the PreferredGraphicsProfile is set to { <see cref="GraphicsProfile.Level_11_1"/>,
174  /// <see cref="GraphicsProfile.Level_11_0"/>,
175  /// <see cref="GraphicsProfile.Level_10_1"/>,
176  /// <see cref="GraphicsProfile.Level_10_0"/>,
177  /// <see cref="GraphicsProfile.Level_9_3"/>,
178  /// <see cref="GraphicsProfile.Level_9_2"/>,
179  /// <see cref="GraphicsProfile.Level_9_1"/>}
180  /// </remarks>
181  public GraphicsProfile[] PreferredGraphicsProfile { get; set; }
182 
183  /// <summary>
184  /// Gets or sets the shader graphics profile that will be used to compile shaders. See remarks.
185  /// </summary>
186  /// <value>The shader graphics profile.</value>
187  /// <remarks>If this property is not set, the profile used to compile the shader will be taken from the <see cref="GraphicsDevice"/>
188  /// based on the list provided by <see cref="PreferredGraphicsProfile"/></remarks>
189  public GraphicsProfile? ShaderProfile { get; set; }
190 
191  /// <summary>
192  /// Gets or sets the device creation flags that will be used to create the <see cref="GraphicsDevice"/>
193  /// </summary>
194  /// <value>The device creation flags.</value>
196 
197  /// <summary>
198  /// Sets the preferred graphics profile.
199  /// </summary>
200  /// <param name="levels">The levels.</param>
201  /// <seealso cref="PreferredGraphicsProfile"/>
202  public void SetPreferredGraphicsProfile(params GraphicsProfile[] levels)
203  {
204  PreferredGraphicsProfile = levels;
205  }
206 
207  /// <summary>
208  /// Gets or sets a value indicating whether this instance is full screen.
209  /// </summary>
210  /// <value><c>true</c> if this instance is full screen; otherwise, <c>false</c>.</value>
211  public bool IsFullScreen
212  {
213  get
214  {
215  return isFullScreen;
216  }
217 
218  set
219  {
220  if (isFullScreen != value)
221  {
222  isFullScreen = value;
223  deviceSettingsChanged = true;
224  }
225  }
226  }
227 
228  /// <summary>
229  /// Gets or sets a value indicating whether [prefer multi sampling].
230  /// </summary>
231  /// <value><c>true</c> if [prefer multi sampling]; otherwise, <c>false</c>.</value>
232  public bool PreferMultiSampling
233  {
234  get
235  {
236  return preferMultiSampling;
237  }
238 
239  set
240  {
241  if (preferMultiSampling != value)
242  {
243  preferMultiSampling = value;
244  deviceSettingsChanged = true;
245  }
246  }
247  }
248 
249  /// <summary>
250  /// Gets or sets the preferred back buffer format.
251  /// </summary>
252  /// <value>The preferred back buffer format.</value>
253  public PixelFormat PreferredBackBufferFormat
254  {
255  get
256  {
257  return preferredBackBufferFormat;
258  }
259 
260  set
261  {
262  if (preferredBackBufferFormat != value)
263  {
264  preferredBackBufferFormat = value;
265  deviceSettingsChanged = true;
266  }
267  }
268  }
269 
270  /// <summary>
271  /// Gets or sets the height of the preferred back buffer.
272  /// </summary>
273  /// <value>The height of the preferred back buffer.</value>
274  public int PreferredBackBufferHeight
275  {
276  get
277  {
278  return preferredBackBufferHeight;
279  }
280 
281  set
282  {
283  if (preferredBackBufferHeight != value)
284  {
285  preferredBackBufferHeight = value;
286  isBackBufferToResize = false;
287  deviceSettingsChanged = true;
288  }
289  }
290  }
291 
292  /// <summary>
293  /// Gets or sets the width of the preferred back buffer.
294  /// </summary>
295  /// <value>The width of the preferred back buffer.</value>
296  public int PreferredBackBufferWidth
297  {
298  get
299  {
300  return preferredBackBufferWidth;
301  }
302 
303  set
304  {
305  if (preferredBackBufferWidth != value)
306  {
307  preferredBackBufferWidth = value;
308  isBackBufferToResize = false;
309  deviceSettingsChanged = true;
310  }
311  }
312  }
313 
314  /// <summary>
315  /// Gets or sets the preferred depth stencil format.
316  /// </summary>
317  /// <value>The preferred depth stencil format.</value>
318  public PixelFormat PreferredDepthStencilFormat
319  {
320  get
321  {
322  return preferredDepthStencilFormat;
323  }
324 
325  set
326  {
327  if (preferredDepthStencilFormat != value)
328  {
329  preferredDepthStencilFormat = value;
330  deviceSettingsChanged = true;
331  }
332  }
333  }
334 
335  /// <summary>
336  /// Gets or sets the preferred refresh rate.
337  /// </summary>
338  /// <value>The preferred refresh rate.</value>
339  public Rational PreferredRefreshRate
340  {
341  get
342  {
343  return preferredRefreshRate;
344  }
345 
346  set
347  {
348  if (preferredRefreshRate != value)
349  {
350  preferredRefreshRate = value;
351  deviceSettingsChanged = true;
352  }
353  }
354  }
355 
356  /// <summary>
357  /// The output (monitor) index to use when switching to fullscreen mode. Doesn't have any effect when windowed mode is used.
358  /// </summary>
359  public int PreferredFullScreenOutputIndex
360  {
361  get
362  {
363  return preferredFullScreenOutputIndex;
364  }
365 
366  set
367  {
368  if (preferredFullScreenOutputIndex != value)
369  {
370  preferredFullScreenOutputIndex = value;
371  deviceSettingsChanged = true;
372  }
373  }
374  }
375 
376  /// <summary>
377  /// Gets or sets the supported orientations.
378  /// </summary>
379  /// <value>The supported orientations.</value>
380  public DisplayOrientation SupportedOrientations
381  {
382  get
383  {
384  return supportedOrientations;
385  }
386 
387  set
388  {
389  if (supportedOrientations != value)
390  {
391  supportedOrientations = value;
392  deviceSettingsChanged = true;
393  }
394  }
395  }
396 
397  /// <summary>
398  /// Gets or sets a value indicating whether [synchronize with vertical retrace].
399  /// </summary>
400  /// <value><c>true</c> if [synchronize with vertical retrace]; otherwise, <c>false</c>.</value>
401  public bool SynchronizeWithVerticalRetrace
402  {
403  get
404  {
405  return synchronizeWithVerticalRetrace;
406  }
407  set
408  {
409  if (synchronizeWithVerticalRetrace != value)
410  {
411  synchronizeWithVerticalRetrace = value;
412  deviceSettingsChanged = true;
413  }
414  }
415  }
416 
417  #endregion
418 
419  #region Public Methods and Operators
420 
421  /// <summary>
422  /// Applies the changes from this instance and change or create the <see cref="GraphicsDevice"/> according to the new values.
423  /// </summary>
424  public void ApplyChanges()
425  {
426  if (GraphicsDevice == null || deviceSettingsChanged)
427  {
428  ChangeOrCreateDevice(false);
429  }
430  }
431 
432  bool IGraphicsDeviceManager.BeginDraw()
433  {
434  if (GraphicsDevice == null)
435  {
436  return false;
437  }
438 
439  beginDrawOk = false;
440 
441  if (!CheckDeviceState())
442  return false;
443 
444  GraphicsDevice.Begin();
445 
446  // Before drawing, we should clear the state to make sure that there is no unstable graphics device states (On some WP8 devices for example)
447  // An application should not rely on previous state (last frame...etc.) after BeginDraw.
448  GraphicsDevice.ClearState();
449 
450  // By default, we setup the render target to the back buffer, and the viewport as well.
451  if (GraphicsDevice.BackBuffer != null)
452  {
453  GraphicsDevice.SetRenderTarget(GraphicsDevice.DepthStencilBuffer, GraphicsDevice.BackBuffer);
454  }
455 
456  beginDrawOk = true;
457  return beginDrawOk;
458  }
459 
460  private bool CheckDeviceState()
461  {
462  switch (GraphicsDevice.GraphicsDeviceStatus)
463  {
464  case GraphicsDeviceStatus.Removed:
465  Utilities.Sleep(TimeSpan.FromMilliseconds(20));
466  return false;
467  case GraphicsDeviceStatus.Reset:
468  Utilities.Sleep(TimeSpan.FromMilliseconds(20));
469  try
470  {
471  ChangeOrCreateDevice(true);
472  }
473  catch (Exception)
474  {
475  return false;
476  }
477  break;
478  }
479 
480  return true;
481  }
482 
483  void IGraphicsDeviceManager.CreateDevice()
484  {
485  // Force the creation of the device
486  ChangeOrCreateDevice(true);
487  }
488 
489  void IGraphicsDeviceManager.EndDraw(bool present)
490  {
491  if (beginDrawOk && GraphicsDevice != null)
492  {
493  if (present && GraphicsDevice.Presenter != null)
494  {
495  try
496  {
497  GraphicsDevice.Presenter.Present();
498  }
499  catch (GraphicsException ex)
500  {
501  // If this is not a DeviceRemoved or DeviceReset, than throw an exception
502  if (ex.Status != GraphicsDeviceStatus.Removed && ex.Status != GraphicsDeviceStatus.Reset)
503  {
504  throw;
505  }
506  }
507  finally
508  {
509  beginDrawOk = false;
510  GraphicsDevice.End();
511  }
512  }
513  }
514  }
515 
516  #endregion
517 
518  protected static DisplayOrientation SelectOrientation(DisplayOrientation orientation, int width, int height, bool allowLandscapeLeftAndRight)
519  {
520  if (orientation != DisplayOrientation.Default)
521  {
522  return orientation;
523  }
524 
525  if (width <= height)
526  {
527  return DisplayOrientation.Portrait;
528  }
529 
530  if (allowLandscapeLeftAndRight)
531  {
532  return DisplayOrientation.LandscapeRight | DisplayOrientation.LandscapeLeft;
533  }
534 
535  return DisplayOrientation.LandscapeRight;
536  }
537 
538  protected override void Destroy()
539  {
540  if (game != null)
541  {
542  if (game.Services.GetService(typeof(IGraphicsDeviceService)) == this)
543  {
544  game.Services.RemoveService(typeof(IGraphicsDeviceService));
545  }
546 
547  game.Window.ClientSizeChanged -= Window_ClientSizeChanged;
548  game.Window.OrientationChanged -= Window_OrientationChanged;
549  }
550 
551  if (GraphicsDevice != null)
552  {
553  if (GraphicsDevice.Presenter != null)
554  {
555  // Make sure that the Presenter is reverted to window before shuting down
556  // otherwise the Direct3D11.Device will generate an exception on Dispose()
557  GraphicsDevice.Presenter.IsFullScreen = false;
558  GraphicsDevice.Presenter.Dispose();
559  GraphicsDevice.Presenter = null;
560  }
561 
562  GraphicsDevice.Dispose();
563  GraphicsDevice = null;
564  }
565 
566  base.Destroy();
567  }
568 
569  /// <summary>
570  /// Determines whether this instance is compatible with the the specified new <see cref="GraphicsDeviceInformation"/>.
571  /// </summary>
572  /// <param name="newDeviceInfo">The new device info.</param>
573  /// <returns><c>true</c> if this instance this instance is compatible with the the specified new <see cref="GraphicsDeviceInformation"/>; otherwise, <c>false</c>.</returns>
574  protected virtual bool CanResetDevice(GraphicsDeviceInformation newDeviceInfo)
575  {
576  // By default, a reset is compatible when we stay under the same graphics profile.
577  return GraphicsDevice.Features.Profile == newDeviceInfo.GraphicsProfile;
578  }
579 
580  /// <summary>
581  /// Finds the best device that is compatible with the preferences defined in this instance.
582  /// </summary>
583  /// <param name="anySuitableDevice">if set to <c>true</c> a device can be selected from any existing adapters, otherwise, it will select only from default adapter.</param>
584  /// <returns>The graphics device information.</returns>
585  protected virtual GraphicsDeviceInformation FindBestDevice(bool anySuitableDevice)
586  {
587  // Setup preferred parameters before passing them to the factory
588  var preferredParameters = new GameGraphicsParameters
589  {
590  PreferredBackBufferWidth = PreferredBackBufferWidth,
591  PreferredBackBufferHeight = PreferredBackBufferHeight,
592  PreferredBackBufferFormat = PreferredBackBufferFormat,
593  PreferredDepthStencilFormat = PreferredDepthStencilFormat,
594  PreferredRefreshRate = PreferredRefreshRate,
595  PreferredFullScreenOutputIndex = PreferredFullScreenOutputIndex,
596  IsFullScreen = IsFullScreen,
597  PreferMultiSampling = PreferMultiSampling,
598  SynchronizeWithVerticalRetrace = SynchronizeWithVerticalRetrace,
599  PreferredGraphicsProfile = (GraphicsProfile[])PreferredGraphicsProfile.Clone(),
600  };
601 
602  // Setup resized value if there is a resize pending
603  if (!IsFullScreen && isBackBufferToResize)
604  {
605  preferredParameters.PreferredBackBufferWidth = resizedBackBufferWidth;
606  preferredParameters.PreferredBackBufferHeight = resizedBackBufferHeight;
607  }
608 
609  var devices = graphicsDeviceFactory.FindBestDevices(preferredParameters);
610  if (devices.Count == 0)
611  {
612  throw new InvalidOperationException("No screen modes found");
613  }
614 
615  RankDevices(devices);
616 
617  if (devices.Count == 0)
618  {
619  throw new InvalidOperationException("No screen modes found after ranking");
620  }
621  return devices[0];
622  }
623 
624  /// <summary>
625  /// Ranks a list of <see cref="GraphicsDeviceInformation"/> before creating a new device.
626  /// </summary>
627  /// <param name="foundDevices">The list of devices that can be reorder.</param>
628  protected virtual void RankDevices(List<GraphicsDeviceInformation> foundDevices)
629  {
630  // Don't sort if there is a single device (mostly for XAML/WP8)
631  if (foundDevices.Count == 1)
632  {
633  return;
634  }
635 
636  foundDevices.Sort(
637  (left, right) =>
638  {
639  var leftParams = left.PresentationParameters;
640  var rightParams = right.PresentationParameters;
641 
642  var leftAdapter = left.Adapter;
643  var rightAdapter = right.Adapter;
644 
645  // Sort by GraphicsProfile
646  if (left.GraphicsProfile != right.GraphicsProfile)
647  {
648  return left.GraphicsProfile <= right.GraphicsProfile ? 1 : -1;
649  }
650 
651  // Sort by FullScreen mode
652  if (leftParams.IsFullScreen != rightParams.IsFullScreen)
653  {
654  return IsFullScreen != leftParams.IsFullScreen ? 1 : -1;
655  }
656 
657  // Sort by BackBufferFormat
658  int leftFormat = CalculateRankForFormat(leftParams.BackBufferFormat);
659  int rightFormat = CalculateRankForFormat(rightParams.BackBufferFormat);
660  if (leftFormat != rightFormat)
661  {
662  return leftFormat >= rightFormat ? 1 : -1;
663  }
664 
665  // Sort by MultiSampleCount
666  if (leftParams.MultiSampleCount != rightParams.MultiSampleCount)
667  {
668  return leftParams.MultiSampleCount <= rightParams.MultiSampleCount ? 1 : -1;
669  }
670 
671  // Sort by AspectRatio
672  var targetAspectRatio = (PreferredBackBufferWidth == 0) || (PreferredBackBufferHeight == 0) ? (float)DefaultBackBufferWidth / DefaultBackBufferHeight : (float)PreferredBackBufferWidth / PreferredBackBufferHeight;
673  var leftDiffRatio = Math.Abs(((float)leftParams.BackBufferWidth / leftParams.BackBufferHeight) - targetAspectRatio);
674  var rightDiffRatio = Math.Abs(((float)rightParams.BackBufferWidth / rightParams.BackBufferHeight) - targetAspectRatio);
675  if (Math.Abs(leftDiffRatio - rightDiffRatio) > 0.2f)
676  {
677  return leftDiffRatio >= rightDiffRatio ? 1 : -1;
678  }
679 
680  // Sort by PixelCount
681  int leftPixelCount;
682  int rightPixelCount;
683  if (IsFullScreen)
684  {
685  if ( ((PreferredBackBufferWidth == 0) || (PreferredBackBufferHeight == 0)) &&
686  PreferredFullScreenOutputIndex < leftAdapter.Outputs.Length &&
687  PreferredFullScreenOutputIndex < rightAdapter.Outputs.Length)
688  {
689  // assume we got here only adapters that have the needed number of outputs:
690  var leftOutput = leftAdapter.Outputs[PreferredFullScreenOutputIndex];
691  var rightOutput = rightAdapter.Outputs[PreferredFullScreenOutputIndex];
692 
693  leftPixelCount = leftOutput.CurrentDisplayMode.Width * leftOutput.CurrentDisplayMode.Height;
694  rightPixelCount = rightOutput.CurrentDisplayMode.Width * rightOutput.CurrentDisplayMode.Height;
695  }
696  else
697  {
698  leftPixelCount = rightPixelCount = PreferredBackBufferWidth * PreferredBackBufferHeight;
699  }
700  }
701  else if ((PreferredBackBufferWidth == 0) || (PreferredBackBufferHeight == 0))
702  {
703  leftPixelCount = rightPixelCount = DefaultBackBufferWidth * DefaultBackBufferHeight;
704  }
705  else
706  {
707  leftPixelCount = rightPixelCount = PreferredBackBufferWidth * PreferredBackBufferHeight;
708  }
709 
710  int leftDeltaPixelCount = Math.Abs((leftParams.BackBufferWidth * leftParams.BackBufferHeight) - leftPixelCount);
711  int rightDeltaPixelCount = Math.Abs((rightParams.BackBufferWidth * rightParams.BackBufferHeight) - rightPixelCount);
712  if (leftDeltaPixelCount != rightDeltaPixelCount)
713  {
714  return leftDeltaPixelCount >= rightDeltaPixelCount ? 1 : -1;
715  }
716 
717  // Sort by default Adapter, default adapter first
718  if (left.Adapter != right.Adapter)
719  {
720  if (left.Adapter.IsDefaultAdapter)
721  {
722  return -1;
723  }
724 
725  if (right.Adapter.IsDefaultAdapter)
726  {
727  return 1;
728  }
729  }
730 
731  return 0;
732  });
733  }
734 
735  private int CalculateRankForFormat(PixelFormat format)
736  {
737  if (format == PreferredBackBufferFormat)
738  {
739  return 0;
740  }
741 
742  if (CalculateFormatSize(format) == CalculateFormatSize(PreferredBackBufferFormat))
743  {
744  return 1;
745  }
746 
747  return int.MaxValue;
748  }
749 
750  private int CalculateFormatSize(PixelFormat format)
751  {
752  switch (format)
753  {
754  case PixelFormat.R8G8B8A8_UNorm:
755  case PixelFormat.R8G8B8A8_UNorm_SRgb:
756  case PixelFormat.B8G8R8A8_UNorm:
757  case PixelFormat.B8G8R8A8_UNorm_SRgb:
758  case PixelFormat.R10G10B10A2_UNorm:
759  return 32;
760 
761  case PixelFormat.B5G6R5_UNorm:
762  case PixelFormat.B5G5R5A1_UNorm:
763  return 16;
764  }
765 
766  return 0;
767  }
768 
769  protected virtual void OnDeviceCreated(object sender, EventArgs args)
770  {
771  var handler = DeviceCreated;
772  if (handler != null)
773  {
774  handler(sender, args);
775  }
776  }
777 
778  protected virtual void OnDeviceDisposing(object sender, EventArgs args)
779  {
780  var handler = DeviceDisposing;
781  if (handler != null)
782  {
783  handler(sender, args);
784  }
785  }
786 
787  protected virtual void OnDeviceReset(object sender, EventArgs args)
788  {
789  var handler = DeviceReset;
790  if (handler != null)
791  {
792  handler(sender, args);
793  }
794  }
795 
796  protected virtual void OnDeviceResetting(object sender, EventArgs args)
797  {
798  var handler = DeviceResetting;
799  if (handler != null)
800  {
801  handler(sender, args);
802  }
803  }
804 
805  protected virtual void OnPreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs args)
806  {
807  var handler = PreparingDeviceSettings;
808  if (handler != null)
809  {
810  handler(sender, args);
811  }
812  }
813 
814  private void Window_ClientSizeChanged(object sender, EventArgs e)
815  {
816  if (!isChangingDevice && ((game.Window.ClientBounds.Height != 0) || (game.Window.ClientBounds.Width != 0)))
817  {
818  resizedBackBufferWidth = game.Window.ClientBounds.Width;
819  resizedBackBufferHeight = game.Window.ClientBounds.Height;
820  isBackBufferToResize = true;
821  ChangeOrCreateDevice(false);
822  }
823  }
824 
825  void Window_OrientationChanged(object sender, EventArgs e)
826  {
827  if ((!isChangingDevice && ((game.Window.ClientBounds.Height != 0) || (game.Window.ClientBounds.Width != 0))) && (game.Window.CurrentOrientation != currentWindowOrientation))
828  {
829  ChangeOrCreateDevice(false);
830  }
831  }
832 
833 
834  private void CreateDevice(GraphicsDeviceInformation newInfo)
835  {
836  newInfo.PresentationParameters.IsFullScreen = isFullScreen;
837  newInfo.PresentationParameters.PresentationInterval = SynchronizeWithVerticalRetrace ? PresentInterval.One : PresentInterval.Immediate;
838  newInfo.DeviceCreationFlags = DeviceCreationFlags;
839 
840  OnPreparingDeviceSettings(this, new PreparingDeviceSettingsEventArgs(newInfo));
841 
842  // this.ValidateGraphicsDeviceInformation(newInfo);
843 
844  bool deviceRecreate = GraphicsDevice != null;
845 
846  // Notify device is resetting (usually this should result in graphics resources being destroyed)
847  if (deviceRecreate)
848  OnDeviceResetting(this, EventArgs.Empty);
849 
850  // Create (or recreate) the graphics device
851  GraphicsDevice = graphicsDeviceFactory.ChangeOrCreateDevice(GraphicsDevice, newInfo);
852 
853  // Notify device is reset (usually this should result in graphics resources being recreated/reloaded)
854  if (deviceRecreate)
855  OnDeviceReset(this, EventArgs.Empty);
856 
857  GraphicsDevice.ShaderProfile = ShaderProfile;
858 
859  // TODO HANDLE Device Resetting/Reset/Lost
860  //GraphicsDevice.DeviceResetting += GraphicsDevice_DeviceResetting;
861  //GraphicsDevice.DeviceReset += GraphicsDevice_DeviceReset;
862  //GraphicsDevice.DeviceLost += GraphicsDevice_DeviceLost;
863  if (!deviceRecreate)
864  GraphicsDevice.Disposing += GraphicsDevice_Disposing;
865 
866  OnDeviceCreated(this, EventArgs.Empty);
867  }
868 
869  void GraphicsDevice_DeviceResetting(object sender, EventArgs e)
870  {
871  // TODO what to do?
872  }
873 
874  void GraphicsDevice_DeviceReset(object sender, EventArgs e)
875  {
876  // TODO what to do?
877  }
878 
879  void GraphicsDevice_DeviceLost(object sender, EventArgs e)
880  {
881  // TODO what to do?
882  }
883 
884  void GraphicsDevice_Disposing(object sender, EventArgs e)
885  {
886  OnDeviceDisposing(sender, e);
887  }
888 
889  private void ChangeOrCreateDevice(bool forceCreate)
890  {
891  using (var profile = Profiler.Begin(GraphicsDeviceManagerProfilingKeys.CreateDevice))
892  {
893  isChangingDevice = true;
894  int width = game.Window.ClientBounds.Width;
895  int height = game.Window.ClientBounds.Height;
896 
897  bool isBeginScreenDeviceChange = false;
898  try
899  {
900  // Notifies the game window for the new orientation
901  game.Window.SetSupportedOrientations(SelectOrientation(supportedOrientations, PreferredBackBufferWidth, PreferredBackBufferHeight, true));
902 
903  var graphicsDeviceInformation = FindBestDevice(forceCreate);
904  game.Window.BeginScreenDeviceChange(graphicsDeviceInformation.PresentationParameters.IsFullScreen);
905  isBeginScreenDeviceChange = true;
906  bool needToCreateNewDevice = true;
907 
908  // If we are not forced to create a new device and this is already an existing GraphicsDevice
909  // try to reset and resize it.
910  if (!forceCreate && GraphicsDevice != null)
911  {
912  OnPreparingDeviceSettings(this, new PreparingDeviceSettingsEventArgs(graphicsDeviceInformation));
913  if (CanResetDevice(graphicsDeviceInformation))
914  {
915  try
916  {
917  var newWidth = graphicsDeviceInformation.PresentationParameters.BackBufferWidth;
918  var newHeight = graphicsDeviceInformation.PresentationParameters.BackBufferHeight;
919  var newFormat = graphicsDeviceInformation.PresentationParameters.BackBufferFormat;
920  var newOutputIndex = graphicsDeviceInformation.PresentationParameters.PreferredFullScreenOutputIndex;
921 
922  GraphicsDevice.Presenter.Description.PreferredFullScreenOutputIndex = newOutputIndex;
923  GraphicsDevice.Presenter.Description.RefreshRate = graphicsDeviceInformation.PresentationParameters.RefreshRate;
924  GraphicsDevice.Presenter.Resize(newWidth, newHeight, newFormat);
925 
926  // Change full screen if needed
927  GraphicsDevice.Presenter.IsFullScreen = graphicsDeviceInformation.PresentationParameters.IsFullScreen;
928 
929  needToCreateNewDevice = false;
930  }
931  catch
932  {
933  }
934  }
935  }
936 
937  // If we still need to create a device, then we need to create it
938  if (needToCreateNewDevice)
939  {
940  CreateDevice(graphicsDeviceInformation);
941  }
942 
943  var presentationParameters = GraphicsDevice.Presenter.Description;
944  isReallyFullScreen = presentationParameters.IsFullScreen;
945  if (presentationParameters.BackBufferWidth != 0)
946  {
947  width = presentationParameters.BackBufferWidth;
948  }
949 
950  if (presentationParameters.BackBufferHeight != 0)
951  {
952  height = presentationParameters.BackBufferHeight;
953  }
954 
955  deviceSettingsChanged = false;
956  }
957  finally
958  {
959  if (isBeginScreenDeviceChange)
960  {
961  game.Window.EndScreenDeviceChange(width, height);
962  }
963 
964  currentWindowOrientation = game.Window.CurrentOrientation;
965  isChangingDevice = false;
966  }
967  }
968  }
969  }
970 }
Service providing method to access GraphicsDevice life-cycle.
virtual void RankDevices(List< GraphicsDeviceInformation > foundDevices)
Ranks a list of GraphicsDeviceInformation before creating a new device.
GraphicsDeviceStatus
Describes the current status of a GraphicsDevice.
RenderTarget BackBuffer
Gets the back buffer sets by the current Presenter setup on this device.
virtual void OnDeviceResetting(object sender, EventArgs args)
void SetPreferredGraphicsProfile(params GraphicsProfile[] levels)
Sets the preferred graphics profile.
virtual void OnDeviceDisposing(object sender, EventArgs args)
virtual bool CanResetDevice(GraphicsDeviceInformation newDeviceInfo)
Determines whether this instance is compatible with the the specified new GraphicsDeviceInformation.
DisplayOrientation
Describes the orientation of the display.
Base class for a framework component.
Defines the interface for an object that manages a GraphicsDevice.
ServiceRegistry Services
Gets the service container.
Definition: GameBase.cs:308
virtual void OnDeviceCreated(object sender, EventArgs args)
Performs primitive-based rendering, creates resources, handles system-level variables, adjusts gamma ramp levels, and creates shaders. See The+GraphicsDevice+class to learn more about the class.
static DisplayOrientation SelectOrientation(DisplayOrientation orientation, int width, int height, bool allowLandscapeLeftAndRight)
EventHandler< PreparingDeviceSettingsEventArgs > PreparingDeviceSettings
override void Destroy()
Disposes of object resources.
virtual void OnPreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs args)
void ApplyChanges()
Applies the changes from this instance and change or create the GraphicsDevice according to the new v...
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
Definition: DirectXTexP.h:175
Describess how data will be displayed to the screen.
virtual GraphicsDeviceInformation FindBestDevice(bool anySuitableDevice)
Finds the best device that is compatible with the preferences defined in this instance.
virtual GraphicsPresenter Presenter
Gets or sets the current presenter use by the Present method.
GraphicsProfile
Identifies the set of supported devices for the demo based on device capabilities.
Describes settings to apply before preparing a device for creation, used by GraphicsDeviceManager.OnPreparingDeviceSettings.
PixelFormat
Defines various types of pixel formats.
Definition: PixelFormat.cs:32
virtual void OnDeviceReset(object sender, EventArgs args)
object GetService(Type type)
Gets the instance service providing a specified service.