Member 13780533 Ответов: 1

Проблемы потока C# с opengl и списками!


Так что у меня уже давно есть эта проблема, и я надеюсь, что у вас, ребята, есть решение для нее. Я пытаюсь создать куски через поток, а затем добавить этот кусок в свой список в моем основном классе, где я так рисую этот кусок. Но он терпит неудачу при попытке установить VBO, содержащий вершины Куба, и я получаю это исключение: "система.AccessViolationException'.

Это мой код для куба:
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);
}


Это мой код в моем основном классе:
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();
        }

    }
}


Код для куска:
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);
            }
        }
    }
}


Код для блока:
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();
    }
}


Вот источник:

Что я уже пробовал:

Я попытался переключиться с List<chunk> На ConcurrentBag<chunk>, потому что это потокобезопасно, так что это может быть не проблема. Я довольно новичок в OpenGL и не привык к потокам и тому подобному, оооочень да.

1 Ответов

Рейтинг:
0

Stylianos Polychroniadis

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.