Issue with Flickering. DrawUserIndexedPrimitives.

Hello!

I post here the same issue : https://github.com/MonoGame/MonoGame/issues/5294.

I have some troubles with DrawUserIndexedPrimitives method.

Here you can see an example of flickering. (DirectX)
https://github.com/krasnotsvetov/MonogameRenderBugExample

If I want to set offset in vertex declaration data and indices in DrawUserIndexedPrimitives i will have flickering of mesh which this method will draw.

How can i fix it?
Why can it happend?

P.S: here is video:

Interesting. I’ve tried it out and have the same issues.

I don’t think there is anything to overlook in the code, it’s very short and seems correct to me.

Ok I’ve tinkered around a bit.

First of all I changed it to a normal drawing procedure with a vertex and index buffer set up in front, because I know I have never had problems with these with flickering.

But then I noticed something odd. It seems like the cause is changing the start index of the index buffer. For some reason it seems like it is moved along with the startvertex already.
Then it hit me that it obviously has to be like that, since the former 9th vertex is now the first. So if I set the index buffer to start at the 3rd position it will only display one square. 'Have to check that again

Now the question is why it doesn’t work like tha tin the function you used - DrawUserIndexedPrimitives, where it for some reason accepts a displaced index buffer after a short flickering.

Here is the code, try it for yourself

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

namespace MonogameRenderBugExample
{
    /// <summary>
    /// This is the main type for your game.
    /// </summary>
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        /// <summary>
        /// IF bugScroll equals 0 all OK.
        /// If bugScroll above 0 we can see mesh flickering
        /// </summary>
        int bugScroll = 2;

         
        const int count = 5;
        VertexPosition[] vertices = new VertexPosition[count * 4];
        int[] indices = new int[count * 6];

        private VertexBuffer vBuffer;
        private IndexBuffer iBuffer;

        BasicEffect effect;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {


            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            effect = new BasicEffect(GraphicsDevice);

            for (int i = 0; i < count; i++)
            {
                indices[i * 6 + 0] = (short)(i * 4 + 0);
                indices[i * 6 + 1] = (short)(i * 4 + 1);
                indices[i * 6 + 2] = (short)(i * 4 + 2);

                indices[i * 6 + 3] = (short)(i * 4 + 0);
                indices[i * 6 + 4] = (short)(i * 4 + 2);
                indices[i * 6 + 5] = (short)(i * 4 + 3);
            }



            for (int i = 0; i < count; i++)
            {
                vertices[i * 4 + 0].Position = new Vector3(-1, -1, 0.5f) + new Vector3(i * 2.5f, 5, 0);
                vertices[i * 4 + 1].Position = new Vector3(1, -1, 0.5f) + new Vector3(i * 2.5f, 5, 0);
                vertices[i * 4 + 2].Position = new Vector3(1, 1, 0.5f) + new Vector3(i * 2.5f, 5, 0);
                vertices[i * 4 + 3].Position = new Vector3(-1, 1, 0.5f) + new Vector3(i * 2.5f, 5, 0);
            }

            vBuffer = new VertexBuffer(GraphicsDevice, VertexPosition.VertexDeclaration, count * 4, BufferUsage.None );
            iBuffer = new IndexBuffer(GraphicsDevice, IndexElementSize.ThirtyTwoBits, count*6, BufferUsage.None);

            vBuffer.SetData(vertices);
            iBuffer.SetData(indices);
        }

        protected override void UnloadContent()
        {
            effect.Dispose();
        }

        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);
            effect.World = Matrix.Identity;
            effect.View = Matrix.CreateLookAt(new Vector3(0, 0, -10), new Vector3(0, 0, -9), Vector3.Up);
            effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, GraphicsDevice.Viewport.AspectRatio, 0.1f, 1000f);
            effect.CurrentTechnique.Passes[0].Apply();
            
            //flickering
            //GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, bugScroll * 4, (count - bugScroll) * 4, indices, bugScroll * 6, (count - bugScroll) * 2);

            //not flickering
            GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, bugScroll * 4, (count - bugScroll) * 4, indices, 0, (count - bugScroll) * 2);

            /*
            GraphicsDevice.SetVertexBuffer(vBuffer);
            GraphicsDevice.Indices = iBuffer;

            //All 3 elements
            GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, bugScroll*4,0, (count-bugScroll)*2);

            //Only 1 element
            GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, bugScroll * 4, bugScroll * 6, (count - bugScroll) * 2);

            //GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0,0, count*2);
            */
            base.Draw(gameTime);
        }
    }
}

Yes, i found this yesterday(about indexing) and there is my thoughts:

I have found a way to another render and may be find a bug in source code.
It’s simple to use DrawIndexedPrimitive and set vertex buffer + index buffer to device like as:
GraphicsDevice.Indices = indexBuffer;
GraphicsDevice.SetVertexBuffer(vertexBuffer);
GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, bugScroll * 4 , 0, (count - bugScroll) * 2);

And here we can use different offset for vertices and indices buffers. For example, i use here 0, but we can use a value above zero without bug.

About bug… i see a strange situtation with indexing in DUP method and want to check it…

Here:

We can see a MAGIC constant 2000. If we remove it, bug will dissapear, because the if condition :
“if ((vertexCount + buffer.UserOffset) < buffer.VertexCount)” will false always.
Another way to set in the first branch of “if”:
buffer.SetData(startVertex * vertexDecl.VertexStride, vertexData, vertexOffset, vertexCount, vertexDecl.VertexStride, SetDataOptions.NoOverwrite);

SetDataOptions to SetDataOptions.Discard.

But it isn’t a good solution, because as I say above, i think the bug in “new” indexing inside DUP method. I will check it when I have more free time.

One observation,
I believe we have a Off-by-one bug in the check ‘if ((vertexCount + buffer.UserOffset) < buffer.VertexCount)’
for example , if we draw 1000 vertices and the buffer is 2000, it will always Discard the buffer instead of using it twice.

Does the flickering happen at fixed internals?
Any change if you half or double the default buffer (500 or 4000 from 2000)?

You are drawing 3 quads (3*4=12 vertices), right?
Does the flickering still occur with a default buffer of 2004 ? (2004%12=0)