OpenTK.Core - GL.NamedBufferStorage引发System.AccessViolationException

时间:2017-08-14 13:17:48

标签: c# opengl opentk

简介

我正在关注此tutorial以了解如何在C#中使用OpenGL。一切都运行良好,直到这部分:OpenGL 4 with OpenTK in C# Part 5: Buffers and Triangle。我没有使用与本教程中使用的完全相同的OpenTK。我在这里使用的是与.NET Core兼容的版本:https://www.nuget.org/packages/OpenTK.NETCore/

问题

当我运行程序时,我的控制台显示以下堆栈跟踪:

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at OpenTK.Graphics.OpenGL.GL.NamedBufferStorage[T2](Int32 buffer, Int32 size, T2[] data, BufferStorageFlags flags)
   at Minecraft.RenderObject..ctor(Vertex[] vertices) in d:\users\user\documents\visual studio 2017\Projects\Minecraft\Minecraft\RenderObject.cs:line 22
   at Minecraft.Game.OnLoad(EventArgs e) in d:\users\user\documents\visual studio 2017\Projects\Minecraft\Minecraft\Program.cs:line 42
   at OpenTK.GameWindow.Run(Double updates_per_second, Double frames_per_second)
   at Minecraft.Program.Main(String[] args) in d:\users\user\documents\visual studio 2017\Projects\Minecraft\Minecraft\Program.cs:line 183

代码

我的代码与教程中的代码非常匹配:

RenderObject.cs

using System;
using OpenTK.Graphics.OpenGL;

namespace Minecraft
{
    public class RenderObject : IDisposable
    {
        private bool initialized;
        private readonly int vertexArray;
        private readonly int buffer;
        private readonly int verticeCount;

        public RenderObject(Vertex[] vertices)
        {
            this.verticeCount = vertices.Length;
            this.vertexArray = GL.GenVertexArray();
            this.buffer = GL.GenBuffer();

            GL.BindVertexArray(this.vertexArray);
            GL.BindBuffer(BufferTarget.ArrayBuffer, this.buffer);

            GL.NamedBufferStorage(
                this.buffer,
                Vertex.Size * vertices.Length, // the size needed by this buffer
                vertices, // data to initialize with
                BufferStorageFlags.MapWriteBit); // at this point we will only write to the buffer

            GL.VertexArrayAttribBinding(this.vertexArray, 0, 0);
            GL.EnableVertexArrayAttrib(this.vertexArray, 0);
            GL.VertexArrayAttribFormat(
                this.vertexArray,
                0, // attribute index, from the shader location = 0
                4, // size of attribute, vec4
                VertexAttribType.Float, // contains floats
                false, // does not need to be normalized as it is already, floats ignore this flag anyway
                0); // relative offset, first item

            GL.VertexArrayAttribBinding(this.vertexArray, 1, 0);
            GL.EnableVertexArrayAttrib(this.vertexArray, 1);
            GL.VertexArrayAttribFormat(
                this.vertexArray,
                1, // attribute index, from the shader location = 1
                4, // size of attribute, vec4
                VertexAttribType.Float, // contains floats
                false, // does not need to be normalized as it is already, floats ignore this flag anyway
                16); // relative offset after a vec4

            GL.VertexArrayVertexBuffer(this.vertexArray, 0, this.buffer, IntPtr.Zero, Vertex.Size);

            this.initialized = true;
        }

        public void Render()
        {
            GL.BindVertexArray(this.vertexArray);
            GL.DrawArrays(PrimitiveType.Triangles, 0, this.verticeCount);
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.initialized)
                {
                    GL.DeleteVertexArray(this.vertexArray);
                    GL.DeleteBuffer(this.buffer);
                    this.initialized = false;
                }
            }
        }
    }
}

Program.cs的

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Input;

namespace Minecraft
{
    class Game : GameWindow
    {
        public Game() :
            base(
                800,
                600,
                GraphicsMode.Default,
                string.Empty,
                GameWindowFlags.Default,
                DisplayDevice.Default,
                4,
                5,
                GraphicsContextFlags.ForwardCompatible)
        {
            this.VSync = VSyncMode.On;
        }

        private int program;
        private List<RenderObject> renderObjects = new List<RenderObject>();

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            Vertex[] vertices =
            {
                new Vertex(new Vector4(-0.25f, 0.25f, 0.5f, 1 - 0f), Color4.HotPink),
                new Vertex(new Vector4(0.0f, -0.25f, 0.5f, 1 - 0f), Color4.HotPink),
                new Vertex(new Vector4(0.25f, 0.25f, 0.5f, 1 - 0f), Color4.HotPink),
            };
            this.renderObjects.Add(new RenderObject(vertices));

            this.CursorVisible = true;

            this.program = this.CreateProgram();
            GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
            GL.PatchParameter(PatchParameterInt.PatchVertices, 3);

        }

        {...}

        /// <summary>
        /// Compiles all shaders
        /// </summary>
        /// <returns> An OpenGL program </returns>
        private int CompileShader(ShaderType shaderType, string path)
        {
            // 1. Create the shader object
            var shader = GL.CreateShader(shaderType);
            // 2. Read the shader source from file
            var src = File.ReadAllText(path);
            // 3. Assign the shader source to the shader object
            GL.ShaderSource(shader, src);
            // 4. Compile it so OpenGL can use it :)
            GL.CompileShader(shader);
            // Check if anything was written to the info log during the 
            // compilation of this specific shader and write it to Debug log
            var info = GL.GetShaderInfoLog(shader);
            if (!string.IsNullOrWhiteSpace(info))
            {
                Debug.WriteLine($"{nameof(GL)}.{nameof(GL.CompileShader)} [{shaderType}] had info log: {info}");
            }
            return shader;
        }

        private int CreateProgram()
        {
            var program = GL.CreateProgram();
            var shaders = new List<int>();

            shaders.Add(
                this.CompileShader(
                    ShaderType.VertexShader,
                    @"Components\Shaders\1Vert\vertexShader.vert"));
            shaders.Add(
                this.CompileShader(
                    ShaderType.FragmentShader,
                    @"Components\Shaders\5Frag\fragmentShader.frag"));

            foreach (var shader in shaders)
            {
                GL.AttachShader(program, shader);
            }
            GL.LinkProgram(program);

            var info = GL.GetProgramInfoLog(program);
            if (!string.IsNullOrWhiteSpace(info))
            {
                Debug.WriteLine($"{nameof(GL)}.{nameof(GL.LinkProgram)} had info log: {info}");
            }

            foreach (var shader in shaders)
            {
                GL.AttachShader(program, shader);
                GL.DeleteShader(shader);
            }
            return program;
        }

        protected override void OnRenderFrame(FrameEventArgs e)
        { 
            base.OnRenderFrame(e);

            this.Title = $"FPS: {1.0f / e.Time:0}";

            GL.ClearColor(new Color4 { A = 1.0f, R = 0.1f, G = 0.1f, B = 0.3f });
            // Clear all the buffers to start drawing afresh
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            GL.UseProgram(this.program);

            foreach (var renderObject in this.renderObjects)
            {
                renderObject.Render();
            }

            // Present the rendered scene to the user
            this.SwapBuffers();
        }
    }
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            // the 'using' idiom guarantees proper resource cleanup.
            // We request 60 UpdateFrame events per second, and unlimited
            // RenderFrame events (as fast as the computer can handle).
            using (Game game = new Game())
            {
                game.Run(60);
            }
        }
    }
}

我是OpenGL的新手,所以我不明白这是什么。请帮我。谢谢:))

似乎我的问题与使用哪个版本的OpenGL有关。因为我正在使用NVIDIA Optimus的笔记本电脑上进行开发,所以它选择使用仅具有OpenGL 4.3的Intel HD Graphics 4600,而使用的OpenGL功能是OpenGL 4.5的一部分。

我所做的是迫使Optimus使用支持OpenGL 4.5的NVIDIA GPU启动所有应用程序。现在我的程序启动没有任何问题。

我现在的问题是:

  1. 有没有办法以编程方式强制Optimus使用NVIDIA GPU代替Intel?如果是这样,我如何让我的程序跨平台?
  2. 有没有办法在这里使用较旧版本的OpenGL做我想做的事情?不是每个人都有OpenGL 4.5我相信

0 个答案:

没有答案
相关问题