Click here to Skip to main content
15,887,386 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
So I've had this problem for some time now and I'm hoping you guys have a solution for it. I'm trying to create chunks through a thread, and then add the chunk to my list in my main class, where I so draw the chunk. But it fails when trying to set the VBO that contains the vertices of a cube, and I get this exception: 'System.AccessViolationException'.

This is my code for the cube:
C#
public Cube(Vector3 pos, float dimension)
{
    position = pos;
    dimensions = dimension;

    float cubePos = dimension;
    cube = new VBO(new Vector3[] {
        new Vector3(cubePos, cubePos, -cubePos), new Vector3(-cubePos, cubePos, -cubePos), new Vector3(-cubePos, cubePos, cubePos), new Vector3(cubePos, cubePos, cubePos),
        new Vector3(cubePos, -cubePos, cubePos), new Vector3(-cubePos, -cubePos, cubePos), new Vector3(-cubePos, -cubePos, -cubePos), new Vector3(cubePos, -cubePos, -cubePos),
        new Vector3(cubePos, cubePos, cubePos), new Vector3(-cubePos, cubePos, cubePos), new Vector3(-cubePos, -cubePos, cubePos), new Vector3(cubePos, -cubePos, cubePos),
        new Vector3(cubePos, -cubePos, -cubePos), new Vector3(-cubePos, -cubePos, -cubePos), new Vector3(-cubePos, cubePos, -cubePos), new Vector3(cubePos, cubePos, -cubePos),
        new Vector3(-cubePos, cubePos, cubePos), new Vector3(-cubePos, cubePos, -cubePos), new Vector3(-cubePos, -cubePos, -cubePos), new Vector3(-cubePos, -cubePos, cubePos),
        new Vector3(cubePos, cubePos, -cubePos), new Vector3(cubePos, cubePos, cubePos), new Vector3(cubePos, -cubePos, cubePos), new Vector3(cubePos, -cubePos, -cubePos) });

    color = new VBO(new Vector3[] {
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1),
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1),
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1),
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1),
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1),
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), });

    elements = new VBO(new int[] { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23}, BufferTarget.ElementArrayBuffer);
}


This is my code in my main class:
C#
using System;
using System.Threading;
using System.Windows.Forms;
using System.Collections.Generic;
using OpenGL;
using Tao.FreeGlut;
using System.Collections.Concurrent;

namespace OpenGLTutorial1
{
    public class Game1 : Game
    {
        private Block block;
        private Camera camera;
        private bool left = false, forward = false, back = false, right = false, up = false;

        //private List chunks = new List();
        private ConcurrentBag chunks = new ConcurrentBag();
        private Thread chunkThread;

        private Vector3 nextChunk;
        public override void LoadContent()
        {
            camera = new Camera(new Vector3(0, 50, 0), Quaternion.Identity);
            camera.SetDirection(new Vector3(0, 0, -1));
            //cube1 = new Cube(Vector3.Zero, 1, "dirt.jpg");
            Program.SetCursor(Glut.GLUT_CURSOR_NONE);

            Global.Manager.LoadBlocks("Blocks.xml");

            block = Global.Manager.NewBlock(new Vector3(0, 0, 0), 0);

            chunks.Add(new Chunk(Vector3.Zero, 8));
            chunkThread = new Thread(CreateChunk);
            //chunkThread.SetApartmentState(ApartmentState.STA);
            chunkThread.Start();

            nextChunk = new Vector3(startChunk.X, startChunk.Y, startChunk.Z);

            Program.SetViewMatrix(camera.ViewMatrix);
            base.LoadContent();
        }
        private static float add = 0;
        private static int speed = 5;
        public override void Update(float deltaTime)
        {
            Program.SetViewMatrix(camera.ViewMatrix);

            if (back) camera.MoveRelativeXZ(Vector3.UnitZ * deltaTime * speed);
            if (forward) camera.MoveRelativeXZ(-Vector3.UnitZ * deltaTime * speed);
            if (left) camera.MoveRelativeXZ(-Vector3.UnitX * deltaTime * speed);
            if (right) camera.MoveRelativeXZ(Vector3.UnitX * deltaTime * speed);
            if (up) camera.Move(new Vector3(0, deltaTime * 2.5f, 0));

            /*add += deltaTime*100;
            if (add >= 20)
            {
                CreateChunk();
                add = 0;
            }*/
            base.Update(deltaTime);
        }
        public override void Draw(ref ShaderProgram program)
        {
            block.Draw(ref program);
            foreach (var item in chunks)
            {
                Chunk chunk= (Chunk)item;
                chunk.Draw(ref program);
            }
            base.Draw(ref program);
        }
        public override void OnKeyboardDown(byte key, int x, int y)
        {
            if (key == 'd') right = true;
            else if (key == 'a') left = true;
            else if (key == 'w') forward = true;
            else if (key == 's') back = true;
            else if (key == ' ') up = true;
            base.OnKeyboardDown(key, x, y);
        }
        public override void OnKeyboardUp(byte key, int x, int y)
        {
            if (key == 'd') right = false;
            else if (key == 'a') left = false;
            else if (key == 'w') forward = false;
            else if (key == 's') back = false;
            else if (key == ' ') up = false;
            base.OnKeyboardUp(key, x, y);
        }
        private int prevX = 0, prevY = 0;
        public override void OnMove(int x, int y)
        {
            // if the mouse move event is caused by glutWarpPointer then do nothing
            if (x == prevX && y == prevY) return;
            if (prevX == 0 && prevY == 0)
            {
                Program.WarpPointer(width / 2, height / 2);
                prevX = x;
                prevY = y;
                return;
            }

            // move the camera when the mouse is down
            float yaw = -(x - width / 2) * 0.002f;
            camera.Yaw(yaw);

            float pitch = -(y - height / 2) * 0.002f;
            camera.Pitch(pitch);

            prevX = x;
            prevY = y;
            Program.WarpPointer(width / 2, height / 2);
            base.OnMove(x, y);
        }
        private int layerIndex = 0;
        private int layerDim = 2;
        private int state = 0;
        private Vector3 startChunk = new Vector3(-1, 0, -1);
        private void CreateChunk()
        {
            while (true)
            {
                int size = 8;
                //chunks.Add(new Chunk(new Vector3(nextChunk.X, nextChunk.Y, nextChunk.Z), size));
                //Console.WriteLine(nextChunk.X.ToString() + ", " + nextChunk.Y.ToString() + ", " + nextChunk.Z.ToString());
                AddChunkFromThread(new Vector3(nextChunk.X, nextChunk.Y, nextChunk.Z), size);

                if (state == 0) nextChunk.X++;
                else if (state == 1) nextChunk.Z++;
                else if (state == 2) nextChunk.X--;
                else if (state == 3) nextChunk.Z--;

                layerIndex++;
                if (layerIndex >= layerDim)
                {
                    layerIndex = 0;
                    state++;
                }
                if (state == 4)
                {
                    layerDim += 2;
                    startChunk = new Vector3(startChunk.X - 1, 0, startChunk.Z - 1);
                    nextChunk = new Vector3(startChunk.X, startChunk.Y, startChunk.Z);
                    state = 0;
                }
            }
        }
        private void AddChunkFromThread(Vector3 pos, int size)
        {
            /*if (this.InvokeRequired)
                this.Invoke(new MethodInvoker(AddChunkFromThread));
            else
            {
                chunks.Add(new Chunk(pos, size));
            }*/
            chunks.Add(new Chunk(pos, size));
        }
        public override void OnClose()
        {
            /*for (int i = 0; i < chunks.Count; i++)
            {
                for (int q = 0; q < chunks[i].block.GetLength(1); q++)
                    for (int y = 0; y < chunks[i].block.GetLength(0); y++)
                        chunks[i].block[y, q].Dispose();
            }*/
            if (chunkThread != null) chunkThread.Abort();
            base.OnClose();
        }

    }
}


Code for the Chunk:
C#
using System;
using OpenGL;
using Tao.FreeGlut;
using System.Collections.Concurrent;

namespace OpenGLTutorial1
{
    public class Chunk
    {
        public Vector3 position;
        //public Block[,] block;
        public ConcurrentBag blocks;
        public Vector2 Size;
        public Chunk(Vector3 pos, int size)
        {
            position = pos * new Vector3(size*2, size*2, size*2);
            //block = new Block[size, size];
            blocks = new ConcurrentBag();
            /*for(int z = 0; z < block.GetLength(1); z++)
                for(int x = 0; x < block.GetLength(0); x++)
                {
                    block[x, z] = new Block((x*2)+ position.X, position.Y,(z*2)+ position.Z, 0);
                }*/
            for (int z = 0; z < size; z++)
                for (int x = 0; x < size; x++)
                {
                    blocks.Add(new Block((x * 2) + position.X, position.Y, (z * 2) + position.Z, 0));
                    //block[x, z] = new Block((x * 2) + position.X, position.Y, (z * 2) + position.Z, 0);
                }
            Size = new Vector2(size, size);
        }
        public void Draw(ref ShaderProgram program)
        {
            /*for (int z = 0; z < block.GetLength(1); z++)
                for (int x = 0; x < block.GetLength(0); x++)
                {
                    blocks[x, z].Draw(ref program);
                }*/
            foreach(var item in blocks)
            {
                Block block = (Block)item;
                block.Draw(ref program);
            }
        }
    }
}


Code for Block:
C#
public class Block
{
    public Vector3 position;
    public string name;
    public Texture texture;
    private Cube cube1;
    public Block(float x, float y, float z, int id)
    {
        position = new Vector3(x, y, z);
        cube1 = new Cube(position, 1);
    }
    public void SetTexture(Texture newTexture)
    {
        texture = newTexture;
        cube1.SetTexture(newTexture);
    }
    public void Draw(ref ShaderProgram program)
    {
        cube1.Draw(ref program);
    }
    public void Dispose()
    {
        cube1.Dispose();
    }
}


Here is the source

What I have tried:

I've tried to switch from a List<chunk> to a ConcurrentBag<chunk>, because that is thread safe, so that might not be the problem. I'm pretty new to OpenGL and I'm not used to threads and stuff, sooooo yeah.
Posted
Updated 15-Apr-18 7:35am

1 solution

You should research OpenGL shared context to get a better understanding of how to perform threading in an OpenGL application. I admit I did not look into your code but I believe I can shed some light. You cannot bind and write resources in a thread other than the main UI thread of your application. Think about your problem in terms of what happens when the GPU driver is drawing while at the same time data upload operations to the GPU are performed from another thread. While using shared context allows you to transfer geometry and texture data across threads, on the other hand shader programs, VAOs, VBOs, Framebuffers must be bound and assigned data from the main UI thread only. A common strategy is to thread expensive operations (such as bitmap loading) in order to prepare data for GPU upload and queue the OpenGL requests relevant to that data on the main UI thread (OnUpdateFrame() function most likely). Another important factor you should consider is that sharing resource data using OpenGL shared context is not always supported by all driver implementations.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900