Show More
Commit Description:
Tidy code.
Commit Description:
Tidy code.
References:
File last commit:
Show/Diff file:
Action:
FNA/src/GraphicsDeviceManager.cs
571 lines | 12.9 KiB | text/x-csharp | CSharpLexer
571 lines | 12.9 KiB | text/x-csharp | CSharpLexer
r0 | #region License | |||
/* FNA - XNA4 Reimplementation for Desktop Platforms | ||||
* Copyright 2009-2020 Ethan Lee and the MonoGame Team | ||||
* | ||||
* Released under the Microsoft Public License. | ||||
* See LICENSE for details. | ||||
*/ | ||||
#endregion | ||||
#region Using Statements | ||||
using System; | ||||
using System.Collections.Generic; | ||||
using Microsoft.Xna.Framework.Graphics; | ||||
#endregion | ||||
namespace Microsoft.Xna.Framework | ||||
{ | ||||
public class GraphicsDeviceManager : IGraphicsDeviceService, IDisposable, IGraphicsDeviceManager | ||||
{ | ||||
#region Public Properties | ||||
public GraphicsProfile GraphicsProfile | ||||
{ | ||||
get; | ||||
set; | ||||
} | ||||
public GraphicsDevice GraphicsDevice | ||||
{ | ||||
get | ||||
{ | ||||
return graphicsDevice; | ||||
} | ||||
} | ||||
private bool INTERNAL_isFullScreen; | ||||
public bool IsFullScreen | ||||
{ | ||||
get | ||||
{ | ||||
return INTERNAL_isFullScreen; | ||||
} | ||||
set | ||||
{ | ||||
INTERNAL_isFullScreen = value; | ||||
prefsChanged = true; | ||||
} | ||||
} | ||||
private bool INTERNAL_preferMultiSampling; | ||||
public bool PreferMultiSampling | ||||
{ | ||||
get | ||||
{ | ||||
return INTERNAL_preferMultiSampling; | ||||
} | ||||
set | ||||
{ | ||||
INTERNAL_preferMultiSampling = value; | ||||
prefsChanged = true; | ||||
} | ||||
} | ||||
private SurfaceFormat INTERNAL_preferredBackBufferFormat; | ||||
public SurfaceFormat PreferredBackBufferFormat | ||||
{ | ||||
get | ||||
{ | ||||
return INTERNAL_preferredBackBufferFormat; | ||||
} | ||||
set | ||||
{ | ||||
INTERNAL_preferredBackBufferFormat = value; | ||||
prefsChanged = true; | ||||
} | ||||
} | ||||
private int INTERNAL_preferredBackBufferHeight; | ||||
public int PreferredBackBufferHeight | ||||
{ | ||||
get | ||||
{ | ||||
return INTERNAL_preferredBackBufferHeight; | ||||
} | ||||
set | ||||
{ | ||||
INTERNAL_preferredBackBufferHeight = value; | ||||
prefsChanged = true; | ||||
} | ||||
} | ||||
private int INTERNAL_preferredBackBufferWidth; | ||||
public int PreferredBackBufferWidth | ||||
{ | ||||
get | ||||
{ | ||||
return INTERNAL_preferredBackBufferWidth; | ||||
} | ||||
set | ||||
{ | ||||
INTERNAL_preferredBackBufferWidth = value; | ||||
prefsChanged = true; | ||||
} | ||||
} | ||||
private DepthFormat INTERNAL_preferredDepthStencilFormat; | ||||
public DepthFormat PreferredDepthStencilFormat | ||||
{ | ||||
get | ||||
{ | ||||
return INTERNAL_preferredDepthStencilFormat; | ||||
} | ||||
set | ||||
{ | ||||
INTERNAL_preferredDepthStencilFormat = value; | ||||
prefsChanged = true; | ||||
} | ||||
} | ||||
private bool INTERNAL_synchronizeWithVerticalRetrace; | ||||
public bool SynchronizeWithVerticalRetrace | ||||
{ | ||||
get | ||||
{ | ||||
return INTERNAL_synchronizeWithVerticalRetrace; | ||||
} | ||||
set | ||||
{ | ||||
INTERNAL_synchronizeWithVerticalRetrace = value; | ||||
prefsChanged = true; | ||||
} | ||||
} | ||||
private DisplayOrientation INTERNAL_supportedOrientations; | ||||
public DisplayOrientation SupportedOrientations | ||||
{ | ||||
get | ||||
{ | ||||
return INTERNAL_supportedOrientations; | ||||
} | ||||
set | ||||
{ | ||||
INTERNAL_supportedOrientations = value; | ||||
prefsChanged = true; | ||||
} | ||||
} | ||||
#endregion | ||||
#region Private Variables | ||||
private Game game; | ||||
private GraphicsDevice graphicsDevice; | ||||
private bool drawBegun; | ||||
private bool disposed; | ||||
private bool prefsChanged; | ||||
private bool supportsOrientations; | ||||
private bool useResizedBackBuffer; | ||||
private int resizedBackBufferWidth; | ||||
private int resizedBackBufferHeight; | ||||
#endregion | ||||
#region Public Static Fields | ||||
public static readonly int DefaultBackBufferWidth = 800; | ||||
public static readonly int DefaultBackBufferHeight = 480; | ||||
#endregion | ||||
#region Public Events | ||||
public event EventHandler<EventArgs> Disposed; | ||||
#endregion | ||||
#region IGraphicsDeviceService Events | ||||
public event EventHandler<EventArgs> DeviceCreated; | ||||
public event EventHandler<EventArgs> DeviceDisposing; | ||||
public event EventHandler<EventArgs> DeviceReset; | ||||
public event EventHandler<EventArgs> DeviceResetting; | ||||
public event EventHandler<PreparingDeviceSettingsEventArgs> PreparingDeviceSettings; | ||||
#endregion | ||||
#region Public Constructor | ||||
public GraphicsDeviceManager(Game game) | ||||
{ | ||||
if (game == null) | ||||
{ | ||||
throw new ArgumentNullException("The game cannot be null!"); | ||||
} | ||||
this.game = game; | ||||
INTERNAL_supportedOrientations = DisplayOrientation.Default; | ||||
INTERNAL_preferredBackBufferHeight = DefaultBackBufferHeight; | ||||
INTERNAL_preferredBackBufferWidth = DefaultBackBufferWidth; | ||||
INTERNAL_preferredBackBufferFormat = SurfaceFormat.Color; | ||||
INTERNAL_preferredDepthStencilFormat = DepthFormat.Depth24; | ||||
INTERNAL_synchronizeWithVerticalRetrace = true; | ||||
INTERNAL_preferMultiSampling = false; | ||||
if (game.Services.GetService(typeof(IGraphicsDeviceManager)) != null) | ||||
{ | ||||
throw new ArgumentException("Graphics Device Manager Already Present"); | ||||
} | ||||
game.Services.AddService(typeof(IGraphicsDeviceManager), this); | ||||
game.Services.AddService(typeof(IGraphicsDeviceService), this); | ||||
prefsChanged = true; | ||||
useResizedBackBuffer = false; | ||||
supportsOrientations = FNAPlatform.SupportsOrientationChanges(); | ||||
game.Window.ClientSizeChanged += INTERNAL_OnClientSizeChanged; | ||||
} | ||||
#endregion | ||||
#region Deconstructor | ||||
~GraphicsDeviceManager() | ||||
{ | ||||
Dispose(false); | ||||
} | ||||
#endregion | ||||
#region Dispose Methods | ||||
protected virtual void Dispose(bool disposing) | ||||
{ | ||||
if (!disposed) | ||||
{ | ||||
if (disposing) | ||||
{ | ||||
if (graphicsDevice != null) | ||||
{ | ||||
graphicsDevice.Dispose(); | ||||
graphicsDevice = null; | ||||
} | ||||
} | ||||
if (Disposed != null) | ||||
{ | ||||
Disposed(this, EventArgs.Empty); | ||||
} | ||||
disposed = true; | ||||
} | ||||
} | ||||
void IDisposable.Dispose() | ||||
{ | ||||
Dispose(true); | ||||
GC.SuppressFinalize(this); | ||||
} | ||||
#endregion | ||||
#region Public Methods | ||||
public void ApplyChanges() | ||||
{ | ||||
/* Calling ApplyChanges() before CreateDevice() forces CreateDevice. | ||||
* We can then return early since CreateDevice basically does all of | ||||
* this work for us anyway. | ||||
* | ||||
* Note that if you hit this block, it's probably because you called | ||||
* ApplyChanges in the constructor. The device created here gets | ||||
* destroyed and recreated by the game, so maybe don't do that! | ||||
* | ||||
* -flibit | ||||
*/ | ||||
if (graphicsDevice == null) | ||||
{ | ||||
(this as IGraphicsDeviceManager).CreateDevice(); | ||||
return; | ||||
} | ||||
// ApplyChanges() calls with no actual changes should be ignored. | ||||
if (!prefsChanged && !useResizedBackBuffer) | ||||
{ | ||||
return; | ||||
} | ||||
// Recreate device information before resetting | ||||
GraphicsDeviceInformation gdi = new GraphicsDeviceInformation(); | ||||
gdi.Adapter = graphicsDevice.Adapter; | ||||
gdi.PresentationParameters = graphicsDevice.PresentationParameters.Clone(); | ||||
INTERNAL_CreateGraphicsDeviceInformation(gdi); | ||||
// Prepare the window... | ||||
if (supportsOrientations) | ||||
{ | ||||
game.Window.SetSupportedOrientations( | ||||
INTERNAL_supportedOrientations | ||||
); | ||||
} | ||||
game.Window.BeginScreenDeviceChange( | ||||
gdi.PresentationParameters.IsFullScreen | ||||
); | ||||
game.Window.EndScreenDeviceChange( | ||||
gdi.Adapter.DeviceName, | ||||
gdi.PresentationParameters.BackBufferWidth, | ||||
gdi.PresentationParameters.BackBufferHeight | ||||
); | ||||
// FIXME: Everything below should be before EndScreenDeviceChange! -flibit | ||||
// Reset! | ||||
graphicsDevice.Reset( | ||||
gdi.PresentationParameters, | ||||
gdi.Adapter | ||||
); | ||||
prefsChanged = false; | ||||
} | ||||
public void ToggleFullScreen() | ||||
{ | ||||
IsFullScreen = !IsFullScreen; | ||||
ApplyChanges(); | ||||
} | ||||
#endregion | ||||
#region Protected Methods | ||||
protected virtual void OnDeviceCreated(object sender, EventArgs args) | ||||
{ | ||||
if (DeviceCreated != null) | ||||
{ | ||||
DeviceCreated(sender, args); | ||||
} | ||||
} | ||||
protected virtual void OnDeviceDisposing(object sender, EventArgs args) | ||||
{ | ||||
if (DeviceDisposing != null) | ||||
{ | ||||
DeviceDisposing(sender, args); | ||||
} | ||||
} | ||||
protected virtual void OnDeviceReset(object sender, EventArgs args) | ||||
{ | ||||
if (DeviceReset != null) | ||||
{ | ||||
DeviceReset(sender, args); | ||||
} | ||||
} | ||||
protected virtual void OnDeviceResetting(object sender, EventArgs args) | ||||
{ | ||||
if (DeviceResetting != null) | ||||
{ | ||||
DeviceResetting(sender, args); | ||||
} | ||||
} | ||||
protected virtual void OnPreparingDeviceSettings( | ||||
object sender, | ||||
PreparingDeviceSettingsEventArgs args | ||||
) { | ||||
if (PreparingDeviceSettings != null) | ||||
{ | ||||
PreparingDeviceSettings(sender, args); | ||||
} | ||||
} | ||||
protected virtual bool CanResetDevice( | ||||
GraphicsDeviceInformation newDeviceInfo | ||||
) { | ||||
throw new NotImplementedException(); | ||||
} | ||||
protected virtual GraphicsDeviceInformation FindBestDevice( | ||||
bool anySuitableDevice | ||||
) { | ||||
throw new NotImplementedException(); | ||||
} | ||||
protected virtual void RankDevices( | ||||
List<GraphicsDeviceInformation> foundDevices | ||||
) { | ||||
throw new NotImplementedException(); | ||||
} | ||||
#endregion | ||||
#region Private Methods | ||||
private void INTERNAL_OnClientSizeChanged(object sender, EventArgs e) | ||||
{ | ||||
Rectangle size = (sender as GameWindow).ClientBounds; | ||||
resizedBackBufferWidth = size.Width; | ||||
resizedBackBufferHeight = size.Height; | ||||
if (Environment.GetEnvironmentVariable("FNA_GRAPHICS_ENABLE_HIGHDPI") == "1") | ||||
{ | ||||
resizedBackBufferWidth *= 2; | ||||
resizedBackBufferHeight *= 2; | ||||
} | ||||
useResizedBackBuffer = true; | ||||
ApplyChanges(); | ||||
} | ||||
private void INTERNAL_CreateGraphicsDeviceInformation( | ||||
GraphicsDeviceInformation gdi | ||||
) { | ||||
/* Apply the GraphicsDevice changes to the new Parameters. | ||||
* Note that PreparingDeviceSettings can override any of these! | ||||
* -flibit | ||||
*/ | ||||
if (useResizedBackBuffer) | ||||
{ | ||||
gdi.PresentationParameters.BackBufferWidth = | ||||
resizedBackBufferWidth; | ||||
gdi.PresentationParameters.BackBufferHeight = | ||||
resizedBackBufferHeight; | ||||
useResizedBackBuffer = false; | ||||
} | ||||
else | ||||
{ | ||||
if (!supportsOrientations) | ||||
{ | ||||
gdi.PresentationParameters.BackBufferWidth = | ||||
PreferredBackBufferWidth; | ||||
gdi.PresentationParameters.BackBufferHeight = | ||||
PreferredBackBufferHeight; | ||||
} | ||||
else | ||||
{ | ||||
/* Flip the backbuffer dimensions to scale | ||||
* appropriately to the current orientation. | ||||
*/ | ||||
int min = Math.Min(PreferredBackBufferWidth, PreferredBackBufferHeight); | ||||
int max = Math.Max(PreferredBackBufferWidth, PreferredBackBufferHeight); | ||||
if (gdi.PresentationParameters.DisplayOrientation == DisplayOrientation.Portrait) | ||||
{ | ||||
gdi.PresentationParameters.BackBufferWidth = min; | ||||
gdi.PresentationParameters.BackBufferHeight = max; | ||||
} | ||||
else | ||||
{ | ||||
gdi.PresentationParameters.BackBufferWidth = max; | ||||
gdi.PresentationParameters.BackBufferHeight = min; | ||||
} | ||||
} | ||||
} | ||||
gdi.PresentationParameters.BackBufferFormat = | ||||
PreferredBackBufferFormat; | ||||
gdi.PresentationParameters.DepthStencilFormat = | ||||
PreferredDepthStencilFormat; | ||||
gdi.PresentationParameters.IsFullScreen = | ||||
IsFullScreen; | ||||
gdi.PresentationParameters.PresentationInterval = | ||||
SynchronizeWithVerticalRetrace ? | ||||
PresentInterval.One : | ||||
PresentInterval.Immediate; | ||||
if (!PreferMultiSampling) | ||||
{ | ||||
gdi.PresentationParameters.MultiSampleCount = 0; | ||||
} | ||||
else if (gdi.PresentationParameters.MultiSampleCount == 0) | ||||
{ | ||||
/* XNA4 seems to have an upper limit of 8, but I'm willing to | ||||
* limit this only in GraphicsDeviceManager's default setting. | ||||
* If you want even higher values, Reset() with a custom value. | ||||
* -flibit | ||||
*/ | ||||
int maxMultiSampleCount = 0; | ||||
if (graphicsDevice != null) | ||||
{ | ||||
maxMultiSampleCount = graphicsDevice.GLDevice.MaxMultiSampleCount; | ||||
} | ||||
gdi.PresentationParameters.MultiSampleCount = Math.Min( | ||||
maxMultiSampleCount, | ||||
8 | ||||
); | ||||
} | ||||
gdi.GraphicsProfile = GraphicsProfile; | ||||
// Give the user a chance to override the above settings. | ||||
OnPreparingDeviceSettings( | ||||
this, | ||||
new PreparingDeviceSettingsEventArgs(gdi) | ||||
); | ||||
} | ||||
#endregion | ||||
#region IGraphicsDeviceManager Methods | ||||
void IGraphicsDeviceManager.CreateDevice() | ||||
{ | ||||
// This function can recreate the device from scratch! | ||||
if (graphicsDevice != null) | ||||
{ | ||||
graphicsDevice.Dispose(); | ||||
graphicsDevice = null; | ||||
} | ||||
// Set the default device information | ||||
GraphicsDeviceInformation gdi = new GraphicsDeviceInformation(); | ||||
gdi.Adapter = GraphicsAdapter.DefaultAdapter; | ||||
gdi.PresentationParameters = new PresentationParameters(); | ||||
gdi.PresentationParameters.DeviceWindowHandle = game.Window.Handle; | ||||
INTERNAL_CreateGraphicsDeviceInformation(gdi); | ||||
// Prepare the window... | ||||
if (supportsOrientations) | ||||
{ | ||||
game.Window.SetSupportedOrientations( | ||||
INTERNAL_supportedOrientations | ||||
); | ||||
} | ||||
game.Window.BeginScreenDeviceChange( | ||||
gdi.PresentationParameters.IsFullScreen | ||||
); | ||||
game.Window.EndScreenDeviceChange( | ||||
gdi.Adapter.DeviceName, | ||||
gdi.PresentationParameters.BackBufferWidth, | ||||
gdi.PresentationParameters.BackBufferHeight | ||||
); | ||||
// FIXME: Everything below should be before EndScreenDeviceChange! -flibit | ||||
// Create the GraphicsDevice, hook the callbacks | ||||
graphicsDevice = new GraphicsDevice( | ||||
gdi.Adapter, | ||||
gdi.GraphicsProfile, | ||||
gdi.PresentationParameters | ||||
); | ||||
graphicsDevice.Disposing += OnDeviceDisposing; | ||||
graphicsDevice.DeviceResetting += OnDeviceResetting; | ||||
graphicsDevice.DeviceReset += OnDeviceReset; | ||||
// Call the DeviceCreated Event | ||||
OnDeviceCreated(this, EventArgs.Empty); | ||||
} | ||||
bool IGraphicsDeviceManager.BeginDraw() | ||||
{ | ||||
if (graphicsDevice == null) | ||||
{ | ||||
return false; | ||||
} | ||||
graphicsDevice.GLDevice.BeginFrame(); | ||||
drawBegun = true; | ||||
return true; | ||||
} | ||||
void IGraphicsDeviceManager.EndDraw() | ||||
{ | ||||
if (graphicsDevice != null && drawBegun) | ||||
{ | ||||
drawBegun = false; | ||||
graphicsDevice.Present(); | ||||
} | ||||
} | ||||
#endregion | ||||
} | ||||
} | ||||