I get around 200FPS, so a bit better than with BasicEffect, but more or less what I had with the previous version (1 BasicEffect per Square).
Once again, I might have missed some optimizations, here is the full source code :
using System;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Patapits.Framework.RawTests
{
public class Square
{
private static Vector3[] _vertices;
private static short[] _indexes;
private Vector2 _position;
public Square()
{
Generate();
}
public void MoveTo(Vector2 position)
{
_position = position;
}
public void Generate()
{
if (_vertices == null)
{
_vertices = new Vector3[4];
_vertices[0] = new Vector3(-0.5f, -0.5f, 0.0f);
_vertices[1] = new Vector3(0.5f, -0.5f, 0.0f);
_vertices[2] = new Vector3(-0.5f, 0.5f, 0.0f);
_vertices[3] = new Vector3(0.5f, 0.5f, 0.0f);
_indexes = new short[6];
_indexes[0] = 0;
_indexes[1] = 1;
_indexes[2] = 2;
_indexes[3] = 1;
_indexes[4] = 3;
_indexes[5] = 2;
}
}
public Matrix GetWorldMatrix()
{
return Matrix.CreateRotationZ(MathHelper.Pi / 3) *
Matrix.CreateScale(100.0f, 100.0f, 1.0f) *
Matrix.CreateTranslation(new Vector3(_position, 0.0f));
}
public VertexPositionColorTexture[] GetVertices()
{
Matrix worldMatrix = GetWorldMatrix();
return _vertices.Select(v =>
new VertexPositionColorTexture(Vector3.Transform(v, worldMatrix), Color.Red, new Vector2(0.0f)))
.ToArray();
}
public short[] GetIndexes()
{
return _indexes;
}
public void Draw(GraphicsDevice device)
{
}
}
public class Game1 : Game
{
GraphicsDeviceManager _graphics;
private Square[] _squares;
private SpriteEffect _effect;
private Texture2D _whiteTexture;
public Game1()
{
_graphics = new GraphicsDeviceManager(this) {SynchronizeWithVerticalRetrace = false};
_graphics.PreferredBackBufferWidth = 1920;
_graphics.PreferredBackBufferHeight = 1080;
IsFixedTimeStep = false;
Content.RootDirectory = "Content";
Window.AllowUserResizing = true;
}
protected override void Initialize()
{
_effect = new SpriteEffect(GraphicsDevice);
_whiteTexture = new Texture2D(GraphicsDevice, 1, 1);
_whiteTexture.SetData(new[] {Color.White});
base.Initialize();
}
protected override void LoadContent()
{
int squaresCount = 100;
_squares = new Square[squaresCount];
Random rand = new Random();
for (int i = 0; i < squaresCount; i++)
{
_squares[i] = new Square();
_squares[i].MoveTo(
new Vector2(
rand.Next(0, _graphics.PreferredBackBufferWidth),
rand.Next(0, _graphics.PreferredBackBufferHeight)));
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.White);
VertexPositionColorTexture[][] squaresVertices = new VertexPositionColorTexture[_squares.Length][];
short[][] squaresIndexes = new short[_squares.Length][];
for (int i = 0; i < _squares.Length; i++)
{
squaresVertices[i] = _squares[i].GetVertices();
squaresIndexes[i] = _squares[i].GetIndexes();
}
VertexPositionColorTexture[] vertices =
new VertexPositionColorTexture[squaresVertices.Sum(array => array.Length)];
short[] indexes = new short[squaresIndexes.Sum(array => array.Length)];
int currentVerticesIndex = 0;
int currentIndexesIndex = 0;
for (int i = 0; i < _squares.Length; i++)
{
int currentIndexesOffset = currentVerticesIndex;
Array.Copy(squaresVertices[i], 0, vertices, currentVerticesIndex, squaresVertices[i].Length);
currentVerticesIndex += squaresVertices[i].Length;
Array.Copy(squaresIndexes[i].Select(s => (short) (s + currentIndexesOffset)).ToArray(), 0, indexes,
currentIndexesIndex, squaresIndexes[i].Length);
currentIndexesIndex += squaresIndexes[i].Length;
}
GraphicsDevice.BlendState = BlendState.AlphaBlend;
foreach (EffectPass pass in _effect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.Textures[0] = _whiteTexture;
GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length,
indexes, 0, indexes.Length / 3);
}
base.Draw(gameTime);
}
}
}
OK, the performance problem probably lies elsewhere. With an āemptyā game (without any Effect nor SpriteBatch, only GraphicsDevice.Clear(Color.CornflowerBlue); in the overrided Draw()), I get around 300FPS at 1080p, which I found suspicious. Without GraphicsDevice.Clear(Color.CornflowerBlue);, I get āonlyā 400FPS (for a black screen ), with 96,35% of the run time spent in SwapChain.Present.
Iāll try to update the Intel Graphics drivers to see if it helps.
EDIT : after updating the drivers, I get around the same FPS without anyting (~400FPS in Debug). But in Release, I got ~200FPSā¦ Iām losing hope
EDIT 2 : nevermind, in Release mode I was using my dedicated graphic card with some settings on it, after forcing my integrated graphic card, I get the same result : around 400FPS
You could create a new empty project and do nothing but measure fps.
At least youād see if your code has a problem or maybe drivers.
I have a Radeon r7 350x which suprisingly seems to have roughly the same performance as your Intel HD 630. With a new empty project (Desktop GL, Debug) I get roughly 4000 fps on average.
This is the code I used:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
namespace Game1
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.SynchronizeWithVerticalRetrace = false;
graphics.ApplyChanges();
IsFixedTimeStep = false;
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
var framerate = (1 / gameTime.ElapsedGameTime.TotalSeconds);
Console.WriteLine(framerate);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
}
}
}
At default resolution with or without GraphicsDevice.Clear(Color.CornflowerBlue); : ~3000 FPS
At 1080p with GraphicsDevice.Clear(Color.CornflowerBlue); : ~300FPS
At 1080p without GraphicsDevice.Clear(Color.CornflowerBlue); : ~400FPS
On my dedicated graphic card (NVIDIA GeForce GTX 1050), I get suprisingly low FPS, but maybe itās due to some settings or some hardware limitation (since I have a laptop, I think the display screen is internally connected to the Intel graphic card, so when using the NVIDIA one, some informations might pass from one card to another, explaining these low FPS values).
In summary, if an empty project without drawing anything is getting around 400FPS, Iām not surprised to have such ālowā FPS when starting to draw some geometry. But I perhaps Iām exaggerating the geometry draw cost, I donāt knowā¦
Anyway, thanks for your time figuring out these numbers @Finnhax
Well i looked up that card and then i looked up a comparison.
To see how it compared to a older 2016 100$ amd card.
Which curb stomped the hell out of it in every single test.
With an empty OpenGL project, I got more or less the same values, except with graphics.IsFullScreen = true;, with which I got ~1000FPS for the OpenGL project VS ~400FPS for the DirectX one. Interestingā¦
My game will be veeeeery basic, no effects, not lots of textures (maybe not a single one), it should be graphically comparable to Sokobond. And this is why I think targeting 144FPS at 1080p on these kind of cards should be possible without some tricky magic. But once again, Iām just starting game development and understanding how things work behind the scene, so I might be completely wrong (but if thatās the case, I donāt get why ).
Those numbers look fine to me considering your gpu.
Why are you targeting 144 fps? In a 2D game like that itās overkill.
Considering the average User has a 60hz display anyway 60 fps is easily enough.
Iām targetting 144 FPS because it seems like thatās the higher display refresh rate widely available (thatās a feeling from what Iāve seen 4 months ago while looking for a new computer).
My current laptop has a refresh rate of 120Hz, I tried running my game at 60FPS : itās stuttery.
Furthermore, Iām targetting such āhighā FPS because I think itāll lead to a better quality game code : if something is not optimized, I will quickly notice it and I will be able to fix it early. In my experience with performance optimization, the application will then have way less bugs when released. Of course, lots of bugs can still exist, but probably way less than without setting this kind of constraint.
That being said, maybe thatās impossible (or only possible after spending a tremendous amount of time) and I will need to move on. But before moving on, I would like to know if Iām doing something wrong or if thatās expected to have such a FPS drop when simply drawing some vertices
Humm try running this particle instancing test and see what kind of fps you get.
Iāve got it set to 5k particles which are actually instanced quads for this i donāt think you can draw anything faster then with that type of draw call.
Try to set the back buffer to a lower resolution then hit f11 to go into fullscreen.
Try it with and without multisampling on.
I can get massive particles on screen even on this old laptop in the 100k + range in lower resolutions.
Or just post a screen shot back its got most of the info printing to the screen.
My old laptopat 1500 x 500 gets about 100fps with 4x multisampling
(as high as this old thing will go in fullscreen).
I can set the backbuffer to 1080p and run it i get about 32 to 60 fps as this card doesnāt even go up to 1920 x 1080. Pretty sure that my desktop can run this with a few hundred thousand + particles with everything on though.
It seems like we donāt have the same version of MonoGame. I donāt have access to GraphicsDevice.PresentationParameters.HardwareModeSwitch and when trying to run it, I got an Exception : Failed to create graphics device! with the StackTrace :
I canāt get screen capture to work in Fullscreen, but here is a full summary :
At 1500x500 :
MSAA on :
Windowed : 167 FPS
Fullscreen : 192 FPS
MSAA off :
Windowed : 828 FPS
Fullscreen : 900 FPS
At 1920x1080 :
MSAA on :
Windowed : 66 FPS
Fullscreen : 25 FPS (!)
MSAA off :
Windowed : 250 FPS
Fullscreen : 880 FPS (!)
I donāt get some results (the ! ones), but maybe thatās due to Windows doing some things behind my backā¦
Anyway, thatās an interesting result, because I can get 250 FPS at 1920x1080 with that much particles, so I guess 144 FPS for my game is definitely achievable. I will do some more tests with my squares example to see if I can improve it.
Thanks @willmotil !
Add this to that test in update
Replace the code block were you go into full screen with the below code.
Increase the number of particles by a lot i did it to 50 k.
run it.
Its the backbuffer size which is the determining factor not so much the number of draws.
Doing the above will make the hardware screen scaler scale it up causing edges but then thatās what the msaa is for.
One note though at that resolution you are probably better off just using high detail textures and far less aliasing. And a lot of people wont be able to run it in the opposite case unless you offer a minimum settings option that upscales.
Itās better to use ārealā Fullscreen (IsFullscreen = true) than āfakeā Fullscreen (borderless window at screen resolution), except in some weird cases with MSAA on
With the kind of graphics my game will be composed of, MSAA seems like too demanding, Iāll try to see if I can make some less GPU-expensive AA alternatives working as suggested by some people above
Out of curiosity, I tried running my game (1 BasicEffect per shape, with about 200 different shapes) at 1980x1080 :
Well you have a instancing example thats about the fastest way to draw anything. Remember that each of those 5000 dots are actually quads. i.e. rectangles.
On my rx vega i run that with msaa off with a million particles drawn well over 60fps.
The human eye doesnāt really detect much past 60fps some fighter piliots tested being able to detect slight changes at 180 fps but thats pushing the limit of extreme.
Iāve looked into hardware instancing when facing my initial performance problem, but your example is top notch, thanks for that ! I will probably not need it for now, but it will be a useful ressource for me at one point or another
IIRC, human eyes donāt analyze and process static frames, but rather movement. And being used to 60 Hz display, now that I have a 120 Hz one, I can easily tell that there is a big difference in smoothness. I donāt know how I get this feeling, but itās blatant (and the same happened when I switched from 25/30 Hz to 60 Hz).
I tried an implementation of FXAA (with the help of DigitalRune Engine source code), and the result is impressively fast (no changes in FPS with or without it), but the rendering might need some tweaks.
EDIT : OK, actually these numbers are valid only for my NVIDIA GeForce GTX 1050ā¦
I also tried a SMAA (still extracted from the DigitalRune source code), full results for my Intel Graphics HD 630 below (at 960x540) :
So FXAA definitely seems to be the only viable solution, but itās still looking a bit āsharpyā (especially when compared with MSAA which gives the best result IMO).
EDIT 2 : At fullscreen (1080p), none of these techniques gives a satisfactory result, Iām around 100 FPS or lower. Back to R&D
I might have found a way to achieve what I want without any performance drop.
I created a thin outline around my squares, with the outer vertices having a transparent color, the inner vertices being Color.Red. So pixels inbetween square edge and outline will be interpolated, attenuating the sharpness of the square.
Some screenshots :
But Iām not fully convinced it will be a good solution.
PROS
Minimal FPS impact (maybe when drawing millions of polygons it can have an impact, but my game will not be composed of more than 10000 polygons at once)
Itās looking great ! (can be compared to MSAA in my opinion)
CONS
Outlines need to be computed (probably with inward/outward polygon offseting algorithm, already found a C# implementation with Clipper), and it has a pretty high performance cost, so it can not be done each frame => every shape needs to be pre-computed
If I want to scale some shape, outline needs to be recomputed many times to match the scaling progress (otherwise itāll be either blurry - too thick outline - or sharpy - too thin outline)
Outlines thickness needs to be picked wisely, and will depend on screen current resolution (the ratio between game world unit and screen pixel unit change at different resolution) => since the player will be able to resize the game window as he wants, all outlines computation will be to be refreshed at each screen size change, so it can have an minor impact
Does that seems like a good solution ? Isnāt that too āconvolutedā ? Isnāt there any other approachs to achieve something similar (softening polygon edges by changing the color alpha value) at a low performance cost ? I will happily take any thought on this
Oh, and @Jjagg, did you manage to set up an example of an efficient way to draw these squares ? I absolutely want to improve my game development skills but canāt find what mistakes Iāve done
Haha ok that makes sense to me
Iām using SpriteEffect now, Iām at 250 fps for drawing 100 squares at 1080p on fake fullscreen, instead of 150 fps with BasicEffect, so a bit better (but Iāve not run them one in front of the other, so this measure might not be āscientificallyā valid ). Iāll try to use SpriteEffect in my game to see if I can get a significant FPS improvement.