Offset and length were out of bounds for the array when setting a Vector2 array for a shader

I am trying to send a Vector2 array to a shader but get keep getting the following error when calling SpriteBatch.End:

  • System.ArgumentException: 'Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection’

The code where i am sending the data (edited down a bit for clarity):

Vector2[] normals = new Vector2[1024];

// createNormals is only called once
void createNormals() 
{
    for (var i = 0; i < normals.Length; i++)
    {
        normals[i] = new Vector2(0, 0);
    }
    
    addNormal(14, new Vector2(0, 1));
    addNormal(12, new Vector2(0.5f, 1));
    addNormal(78, new Vector2(0.5f, 1));
    addNormal(6, new Vector2(-0.5f, 1));
    addNormal(24, new Vector2(-1f, 1));
    addNormal(94, new Vector2(0f, 1));
    addNormal(4, new Vector2(0f, 1));
    addNormal(76, new Vector2(0f, 1));
    addNormal(30, new Vector2(-0.5f, 1));

    effect.Parameters["normals"].SetValue(normals);
}

public void addNormal(int index, Vector2 normal)
{
    normal.Normalize();
    normals[index] = normal;
}

The shader code:

float2 normals[1024];

// the return value is used elsewhere so normals is not optimized away
float2 getNormal(int i) {
    return normals[i];
}

stackTrace:
at System.Buffer.BlockCopy(Array src, Int32 srcOffset, Array dst, Int32 dstOffset, Int32 count)
at Microsoft.Xna.Framework.Graphics.ConstantBuffer.SetParameter(Int32 offset, EffectParameter param)
at Microsoft.Xna.Framework.Graphics.ConstantBuffer.SetParameter(Int32 offset, EffectParameter param)
at Microsoft.Xna.Framework.Graphics.ConstantBuffer.Update(EffectParameterCollection parameters)
at Microsoft.Xna.Framework.Graphics.EffectPass.Apply()
at Microsoft.Xna.Framework.Graphics.SpriteBatcher.FlushVertexArray(Int32 start, Int32 end, Effect effect, Texture texture)
at Microsoft.Xna.Framework.Graphics.SpriteBatcher.DrawBatch(SpriteSortMode sortMode, Effect effect)
at MyGame.Game1.Draw(GameTime gameTime) in C:\dev\myGame\myGame\MyGame\Game1.cs:line 181
at Microsoft.Xna.Framework.Game.DoDraw(GameTime gameTime)
at Microsoft.Xna.Framework.Game.Tick()
at Microsoft.Xna.Framework.SdlGamePlatform.RunLoop()
at Microsoft.Xna.Framework.Game.Run(GameRunBehavior runBehavior)
at Program.$(String[] args) in C:\dev\myGame\myGame\MyGame\Program.cs:line 3

I am new to writing shaders so maybe i am doing something very stupid and simply not noticing.

This should work.
Is this DirectX or OpenGL?
Which shader model are you using?
Does a smaller array work?

I am using OpenGL with shaderModel vs_3_0 and ps_3_0. Size 16 and 2 do not work either.

I made a new project with the code edited down a lot so i can more easily share it, maybe there is something in here i am doing wrong.

Game1.cs:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace openglarraystest
{
    public class Game1 : Game
    {
        private GraphicsDeviceManager _graphics;
        private SpriteBatch _spriteBatch;

        private Effect effect;
        private Texture2D texture;
        private float[] data = new float[16];

        public Game1()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;
        }

        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();

            texture = Content.Load<Texture2D>("icon");
            effect = Content.Load<Effect>("shader");

            for (var i = 0; i < data.Length; i++)
            {
                data[i] = i;
            }
        }

        protected override void LoadContent()
        {
            _spriteBatch = new SpriteBatch(GraphicsDevice);
            
        }

        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.CornflowerBlue);

            Matrix view = Matrix.Identity;
            int width = GraphicsDevice.Viewport.Width;
            int height = GraphicsDevice.Viewport.Height;
            Matrix projection = Matrix.CreateOrthographicOffCenter(0, width, height, 0, 0, 1);

            effect.Parameters["view_projection"].SetValue(view * projection);
            effect.Parameters["data"].SetValue(data);

            _spriteBatch.Begin(effect: effect);
            _spriteBatch.Draw(texture, new Rectangle(0, 0, 100, 100), Color.White);
            _spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}

shader.fx:

#if OPENGL
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0
#define PS_SHADERMODEL ps_4_0
#endif

float4x4 view_projection;

float data[16];

sampler TextureSampler : register(s0);

struct VertexInput
{
    float4 Position : POSITION0;
    float4 Color : COLOR0;
    float4 TexCoord : TEXCOORD0;
};
struct PixelInput
{
    float4 Position : SV_Position0;
    float4 Color : COLOR0;
    float4 TexCoord : TEXCOORD0;
};

PixelInput SpriteVertexShader(VertexInput v)
{
    PixelInput output;

    output.Position = mul(v.Position, view_projection);
    output.Color = v.Color;
    output.TexCoord = v.TexCoord;
    
    return output;
}

float4 SpritePixelShader(PixelInput p) : SV_TARGET
{
    float4 diffuse = tex2D(TextureSampler, p.TexCoord.xy);

    return diffuse * p.Color * data[0];
}

technique SpriteBatch
{
    pass
    {
        VertexShader = compile VS_SHADERMODEL SpriteVertexShader();
        PixelShader = compile PS_SHADERMODEL SpritePixelShader();
    }
}

You are only using the first element in your shader, so MojoShader “optimizes” your array:

uniform vec4 ps_uniforms_vec4[1];

If you are planning to do more shader programming, and you don’t care for Consoles or Apple platforms, I would suggest to switch to my ShaderConductor branch: Compute, Tessellation & Geometry Shader

1 Like

Thanks a lot i will look into that