Incorrect Screen Resolution in DirectX Windows Project

Hi Guys,

I have fixed resolution of my game to 800/600 but somehow when i run the game in release mode window size is 1014/645 and working fine in debug mode.

I have used below settings in game constructor:

            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferredBackBufferHeight = 600;            

            graphics.ApplyChanges();

Not sure what i am doing wrong. Any insights?

On dx there is a resize problem, otherwise,

You can reference the test link in my post on the bottom of that topic, to see how to do all the windowing stuff like resizing minimizing maximizing the window as well as mode switching.
It will run a auto test but you can disable it then use the F1 thru 12 keys to play around with it after the test run ends. Then just look to the code that executed.

A fix should be merged soon: https://github.com/mono/MonoGame/pull/4959

It doesn’t sound like this is the same problem though…

It doesn’t sound like this is the same problem though…

If its a app in dx monogame it probably is related to that.

Well first off to be clear you don’t really set the backbuffer nor does mg or xna the back buffer is determined by the resolution modes that your graphics card allows. In xna and mg the backbuffer is a drawing area which is scaled to the current resolution either by windows the driver or the card itself.

This is why it is called Preferred PreferedBackBuffer. Width or Height its explicitly named to implicitly lead you to realize that it is going to give you the closest device(gpu) resolution mode match available it can find though this is of little matter if you stay in windowed mode if you goto fullscreen it matters.

You call this first because the first call in the constructors or (device mode) initialization actually finds a suitable mode. After that you can just set the mg BackBuffer which is the modes resolution as it is already selected changing it thru the presentation parameters.

The easiest hack around these problems is to simply at the end of your load create and call a method named something like
SetResolutionAndWindowSize( …)
{
Manually set everything and just call apply changes for the backbuffer use the presentation parameters. Then for the window change the viewport and or the window clientbounds
}

You can still initialize the preferred before that and probably should. Later on then just ensure at the end of load everything is set up properly yourself calling directly to the presentation parameters especially since monogame is a little twitchy right now on this aspect.
Further then if you have a button that changes the backbuffer in your game options or such while your game is running, you call to that method you created.

Honestly i normally just use gl though so until the dx version is behaving correctly im not sure you can fully blame anything your doing on yourself yet i suggest running a test app in gl dx to see if you get a different results / behavior under release between the two before pulling your hair out.

Hi !
I’m using MG 3.6.0.622 (the lastest at the time of this post)
I’m encountering the same problem, setting 800x600 resolution seems to be ignored when switching to fullscreen:
Simple consoles outputs after a call to ApplyChanges:

Console.WriteLine("IsFullScreen:{0}",
	_GFX_GraphicsDevMgr.IsFullScreen);
			
Console.WriteLine("prefw:{0} prefh:{1}", 
	_GFX_GraphicsDevMgr.PreferredBackBufferWidth, 
	_GFX_GraphicsDevMgr.PreferredBackBufferHeight);

Console.WriteLine("ppbbw:{0} ppbbh:{1}", 
	this._GFX_GraphicsDevMgr.GraphicsDevice.PresentationParameters.BackBufferWidth, 
	this._GFX_GraphicsDevMgr.GraphicsDevice.PresentationParameters.BackBufferHeight);

Console.WriteLine("vpw:{0} vph:{1}",
	_GFX_GraphicsDevMgr.GraphicsDevice.Viewport.Width,
	_GFX_GraphicsDevMgr.GraphicsDevice.Viewport.Height);

Console.WriteLine("adapterw:{0} adapterh:{1}",
	_GFX_GraphicsDevMgr.GraphicsDevice.Adapter.CurrentDisplayMode.Width,
	_GFX_GraphicsDevMgr.GraphicsDevice.Adapter.CurrentDisplayMode.Height);

Console.WriteLine("displaymodew:{0} displaymodeh:{1}",
	_GFX_GraphicsDevMgr.GraphicsDevice.DisplayMode.Width,
	_GFX_GraphicsDevMgr.GraphicsDevice.DisplayMode.Height);

gives:

prefw:800 prefh:600
ppbbw:1920 ppbbh:1080
vpw:1920 vph:1080
adapterw:1920 adapterh:1080
displaymodew:1920 displaymodeh:1080

If after this call to ApplyChanges(), I try to set the resolution anothertime after having switched to fullscreen:

this._GFX_GraphicsDevMgr.IsFullScreen = !this._GFX_GraphicsDevMgr.IsFullScreen;
this._GFX_GraphicsDevMgr.ApplyChanges();

this._GFX_GraphicsDevMgr.GraphicsDevice.PresentationParameters.BackBufferWidth = 800;
this._GFX_GraphicsDevMgr.GraphicsDevice.PresentationParameters.BackBufferHeight = 600;
this._GFX_GraphicsDevMgr.ApplyChanges();

gives:

prefw:800 prefh:600
ppbbw:800 ppbbh:600
vpw:800 vph:600
adapterw:1920 adapterh:1080
displaymodew:1920 displaymodeh:1080

Whereas the screen is still displaying in 1920x1080: the displayed text font is as small as in 800x600, but it should be bigger and blurry when going fullscreen. Right ? Same thing for the test texture.

If your windows desktiop can’t change to 800x600 then the game can’t, you need to specify the same aspect ratio as your monitor allows - do this calculation:

  1. 1080/1920 = 0.5625
  2. 800 * (result of 1) 0.5625 = 450
  3. result = 800x450 for the same aspect ration as your 1920x1080 monitor. you should then be able to go full screen at that resolution.

You need to use some sort of adaptor to draw your screen with letter/pillar box style, below is a link that might help:

http://www.david-amador.com/2010/03/xna-2d-independent-resolution-rendering/

Below is the full Resolution.cs code I use now:

//////////////////////////////////////////////////////////////////////////
////License:  The MIT License (MIT)
////Copyright (c) 2010 David Amador (http://www.david-amador.com)
////Direct Link: http://www.david-amador.com/2010/03/xna-2d-independent-resolution-rendering/
////Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
////
////The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
////
////THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Project1
{
	public static class MouseHelper
	{
		/// <summary>
		/// Translates the actual mouse position obtained from Mouse.GetState() into the virtual mouse position after a scaling matrix is applied to the viewport
		/// </summary>
		public static Point CurrentMousePosition
		{
			get
			{
				MouseState mouse = Mouse.GetState();

				var mousePosition = new Vector2(mouse.X, mouse.Y);
				var virtualViewport = new Vector2(Resolution.VirtualViewportX, Resolution.VirtualViewportY);
				mousePosition = Vector2.Transform(mousePosition - virtualViewport, Matrix.Invert(Resolution.GetTransformationMatrix()));

				var virtualMousePosition = new Point((int)mousePosition.X, (int)mousePosition.Y);
				return virtualMousePosition;
			}
		}
	}

	internal static class Resolution
	{
		private static bool _fullScreen = false;
		private static GraphicsDeviceManager _graphicsDevice = null;
		private static bool _recreateScaleMatrix = true;
		private static Matrix _scaleMatrix;
		private static int _screenHeight = 720;  // Actual Screen size
		private static int _screenWidth = 1400;   // Actual Screen size
		private static int _virtualHeight = 720; // Size to display at / design size
		private static int _virtualWidth = 1280; // Size to display at / design size



		static public Rectangle VirtualViewport
		{
			get
			{
				return new Rectangle(0, 0, _virtualWidth, _virtualHeight);
			}
		}

		public static int VirtualViewportX { get; private set; }

		public static int VirtualViewportY { get; private set; }



		/// <summary>
		/// Sets the device to use the draw pump
		/// Sets correct aspect ratio
		/// </summary>
		static public void BeginDraw()
		{
			// Start by reseting viewport to (0,0,1,1)
			FullViewport();
			// Calculate Proper Viewport according to Aspect Ratio
			ResetViewport();
			// Clear to Black
			_graphicsDevice.GraphicsDevice.Clear(Color.Black);
		}

		static public void FullViewport()
		{
			var viewport = new Viewport(0, 0, _screenWidth, _screenHeight);
			_graphicsDevice.GraphicsDevice.Viewport = viewport;
		}

		static public Matrix GetTransformationMatrix()
		{
			if (_recreateScaleMatrix)
			{
				RecreateScaleMatrix();
			}

			return _scaleMatrix;
		}

		/// <summary>
		/// Get virtual Mode Aspect Ratio
		/// </summary>
		/// <returns>aspect ratio</returns>
		static public float GetVirtualAspectRatio()
		{
			return (float)_virtualWidth / (float)_virtualHeight;
		}

		static public void Initialize(GraphicsDeviceManager device)
		{
			_screenWidth = device.PreferredBackBufferWidth;
			_screenHeight = device.PreferredBackBufferHeight;
			_graphicsDevice = device;
			_recreateScaleMatrix = true;
			ApplyResolutionSettings();
		}

		static public void ResetViewport()
		{
			float targetAspectRatio = GetVirtualAspectRatio();
			// figure out the largest area that fits in this resolution at the desired aspect ratio
			int width = _graphicsDevice.PreferredBackBufferWidth;
			int height = (int)(width / targetAspectRatio + .5f);
			bool changed = false;

			if (height > _graphicsDevice.PreferredBackBufferHeight)
			{
				height = _graphicsDevice.PreferredBackBufferHeight;
				// PillarBox
				width = (int)(height * targetAspectRatio + .5f);
				changed = true;
			}

			// set up the new viewport centered in the back buffer
			var viewport = new Viewport();

			viewport.X = (_graphicsDevice.PreferredBackBufferWidth / 2) - (width / 2);
			viewport.Y = (_graphicsDevice.PreferredBackBufferHeight / 2) - (height / 2);
			viewport.Width = width;
			viewport.Height = height;
			viewport.MinDepth = 0;
			viewport.MaxDepth = 1;

			VirtualViewportX = viewport.X;
			VirtualViewportY = viewport.Y;
			if (changed)
			{
				_recreateScaleMatrix = true;
			}
			_graphicsDevice.GraphicsDevice.Viewport = viewport;
		}

		static public void SetResolution(int width, int height, bool fullScreen)
		{
			_screenWidth = width;
			_screenHeight = height;
			_fullScreen = fullScreen;

			ApplyResolutionSettings();
		}

		static public void SetVirtualResolution(int virtualWidth, int virtualHeight)
		{
			_virtualWidth = virtualWidth;
			_virtualHeight = virtualHeight;
			_recreateScaleMatrix = true;
		}



		static private void ApplyResolutionSettings()
		{
#if XBOX360
		   Resolution.fullScreen = true;
#endif

			// If we aren't using a full screen mode, the height and width of the window can
			// be set to anything equal to or smaller than the actual screen size.
			if (_fullScreen == false)
			{
				if ((_screenWidth <= GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width)
					&& (_screenHeight <= GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height))
				{
					_graphicsDevice.PreferredBackBufferWidth = _screenWidth;
					_graphicsDevice.PreferredBackBufferHeight = _screenHeight;
					_graphicsDevice.IsFullScreen = _fullScreen;
					_graphicsDevice.ApplyChanges();
				}
			}
			else
			{
				// If we are using full screen mode, we should check to make sure that the display
				// adapter can handle the video mode we are trying to set.  To do this, we will
				// iterate through the display modes supported by the adapter and check them against
				// the mode we want to set.
				foreach (DisplayMode displayMode in GraphicsAdapter.DefaultAdapter.SupportedDisplayModes)
				{
					// Check the width and height of each mode against the passed values
					if (displayMode.Width == _screenWidth && displayMode.Height == _screenHeight)
					{
						// The mode is supported, so set the buffer formats, apply changes and return
						_graphicsDevice.PreferredBackBufferWidth = _screenWidth;
						_graphicsDevice.PreferredBackBufferHeight = _screenHeight;
						_graphicsDevice.IsFullScreen = _fullScreen;
						_graphicsDevice.ApplyChanges();
						break;
					}
				}
			}
			_recreateScaleMatrix = true;
			_screenWidth = _graphicsDevice.PreferredBackBufferWidth;
			_screenHeight = _graphicsDevice.PreferredBackBufferHeight;
		}

		static private void RecreateScaleMatrix()
		{
			_recreateScaleMatrix = false;
			_scaleMatrix = Matrix.CreateScale(
											(float)_graphicsDevice.GraphicsDevice.Viewport.Width / _virtualWidth,
											(float)_graphicsDevice.GraphicsDevice.Viewport.Height / _virtualHeight,
											1f);
		}
	}
}

Here is the usage I have for using the above class:

Usage:

In your game constructor class use:
{
_graphics = new GraphicsDeviceManager(this);

	Resolution.Initialize(_graphics);
	Resolution.SetVirtualResolution(800, 600);     // Size game is designed for e.g. 800x600
	Resolution.SetResolution(1920, 1080, true);     // Actual size of window to display - If fullscreen, then needs to be valid monitor dimensions
}

*Note because the 800x600 is not the same aspect ration as the monitor you will get black letter/pillar bars.

In your game Draw() method use, which then uses the Matrix created.:

protected override void Draw(GameTime gameTime)
{
	Resolution.BeginDraw();
	_spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, Resolution.GetTransformationMatrix());
	_spriteBatch.End()
}

You will also need to use the mousehelper class to get the mouse X & Y positions:

MouseHelper.CurrentMousePosition.X
MouseHelper.CurrentMousePosition.Y

Hope this helps.

Thanks for your help.
But I dont understand… Why wouldnt I be able to draw in 800x600 in fullscreen ? All video cards nowadays can. It used to work in xna without doing all this. I want the screen to be occupied in its whole, not to keep the aspect ratio with black bands.
It is the same problem with 1024x768 or 1280x720 etc. Moreover they are all in the supported displaymode list of my card (670M)
When switching to fullscreen, it seems all is using the displaymode of the desktop resolution. And as I’m using 1920x1080…

@Alkher I think the problem is because your aspect ration is 0.5625 so when changing the resolution to full screen the only resolutions you can change to has to be in the same ratio - Note I’m fairly new to monogame and understand your issue, but from my testing I’ve had the same problem - however other more experience developers in monogame might know of a way to do it. Use the below for loop to view the display modes you can change to (full version of that is in the resolution class I posted above.

foreach (DisplayMode displayMode in GraphicsAdapter.DefaultAdapter.SupportedDisplayModes) {...}

If you don’t keep the aspect ration, when you draw in 800x600 and display it on a 1920x1080, then the image will be stretched. I believe to do this you would need to set up a camera matrix (though personally I’m not sure how to do that).

I want the image to be stretched, I planned using Independant Resolution later :wink:
I think 800x600 is now the minimum standard, or maybe 1024x768. But what I want for now, is see how fast my engine is in fullscreen: Windowed, an empty window is 350fps, when switching to fullscreen, it drops to 170fps… as it is rendering from 800x600 (windowed) to 1920x1080(fullscreen)

All the “regular” display modes are in the list of the supporteddisplaymode of my card. When I play Painkiller for example, I can set it fullscreen at 800x600, 1280x720, 1280x600 etc with image stretched without problem. I’m pretty sure it is not a ratio related problem but rather monogame using displaymode somewhere in its internal code instead of the backbuffer params. Does any Monogame’s dev have an idea ? :slightly_smiling:

Another strange thing, when i set PreferMultiSampling to true, nothing is display, screen empty… I’ll have to dig into MG Sourcecode to see what’s happening: my code is wrong or MG’s is wrong.

I’ve just tested my code with MG 3.5.1.1679 (latest stable) and switching to fullscreen is ok, the image is 800x600…
It seems there has been a regression between these versions.
Another point:
MG 3.5.1.1679 (latest stable) -> 600fps (average)
MG 3.6.0.622 (the lastest dev at the time of this post) -> 350fps
for the same code: a clear, and a simple texture drawn to test the speed…

It seems the line of code MG’s code at 645 is called only once at startup. I’ve added a simple

Console.WriteLine(GraphicsDevice.PresentationParameters.BackBufferWidth);
Console.WriteLine(GraphicsDevice.PresentationParameters.BackBufferHeight);

Which are seen during initalization (currently my render screen is 800x600, 1920x1080 for the desktop), but when applyChanges is called to togle fullscreen on Enter press, it is never triggered…

Might be related to this #4959.

Have you tried getting the latest dev and testing again?

My previous post concerns the latest version :wink:
It seems related though.

I too am having this problem.

With the current dev branch (3.6.0.715) if IsFullScreen == true, the game simply ignores the PreferredBackBuffer and uses the native resolution of the desktop.

With the current master branch (3.5.1.1679) if IsFullScreen == true, the game correctly changes the resolution to the specified PreferredBackBuffer, but mouse coordinates are still reported incorrectly, using the native resolution of the desktop instead of the resolution of the client window.

OpenGL projects have neither of these issues in 3.6.0.715, but OpenTK had major issues with my multi-monitor setup in 3.5.1 - if fullscreen, the primary display would change resolutions, but the game itself would be displayed on a secondary monitor. For instance:

Display 1: 1920x1080 native (primary)
Display 2: 1440x900 native (secondary)

If the game is set to 800x600, Display 1 would change resolutions to 800x600, but the game would display on Display 2 in 800x600 but the monitor itself did not change resolutions and the game would look like a window without actually being one, since its bounds were set to 800x600. I had this issue both in Windows and Linux. Once I changed to the develop branch using SDL2 instead of OpenTK, everything worked fine, but now DirectX games do not work correctly - fullscreen will only run on the primary monitor at 1920x1080 despite anything the PreferredBackBuffer is set to.