Hello! I’m trying to fill 1920x1080 screen with sprites 16x16 size (120x67 tiles). For testing worst possible scenario i switch texture every tile. I know it is wrong and i should use tilemap and switch texture less often, but it’s only test.
My code is here
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Fna1
{
    public class Tile
    {
        public Texture2D texture;
    }
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D t1;
        Texture2D t2;
        SpriteFont font;
        int sizeX = 120;
        int sizeY = 67;
        Tile[,] tiles;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
        protected override void Initialize()
        {
            graphics.PreferredBackBufferWidth = 1920;
            graphics.PreferredBackBufferHeight = 1080;
            graphics.SynchronizeWithVerticalRetrace = false;
            IsFixedTimeStep = false;
            graphics.ApplyChanges();
            base.Initialize();
        }
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            t1 = GenerateTexture(Color.DarkGreen);
            t2 = GenerateTexture(Color.DarkCyan);
            font = Content.Load<SpriteFont>("font");
            int c = 0;
            tiles = new Tile[sizeX, sizeY];
            for (int x = 0; x < sizeX; x++)
            {
                for (int y = 0; y < sizeY; y++)
                {
                    tiles[x, y] = new Tile();
                    tiles[x, y].texture = (c % 2) == 0 ? t1 : t2;
                    c++;
                }
            }
        }
        private Texture2D GenerateTexture(Color color)
        {
            Texture2D texture = new Texture2D(GraphicsDevice, 16, 16);
            var cdata = new Color[16 * 16];
            for (int i = 0; i < 16; i++)
            {
                for (int j = 0; j < 16; j++)
                {
                    cdata[i * 16 + j] = color;
                }
            }
            texture.SetData(cdata);
            return texture;
        }
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();
            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Transparent);
            spriteBatch.Begin();
            for (int x = 0; x < sizeX; x++)
            {
                for (int y = 0; y < sizeY; y++)
                {
                    spriteBatch.Draw(tiles[x, y].texture, new Vector2(x * 16, y * 16), Color.White);
                }
            }
            spriteBatch.End();
            var fps = 1 / gameTime.ElapsedGameTime.TotalSeconds;
            spriteBatch.Begin();
            spriteBatch.DrawString(font, fps.ToString(), Vector2.Zero, Color.White);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}
On my hardware (Geforce 760 GT) i have about 100 fps in release build. But later i tested the same code on FNA and received 500 fps! Both my projects is net.core 3.1 if it matters.
I checked source code of SpriteBatch.cs on both MonoGame and FNA. And saw that FNA uses DrawIndexedPrimitives and DynamicVertexBuffer instead of DrawUserIndexedPrimitives in Monogame. Then i recreated FNA’s SpriteBatch from source code and make some fixes. And get only 130 fps.
Сan someone explain to me what’s the matter?
