OpenTK.Core - GL.NamedBufferStorage raises System.AccessViolationException

独自空忆成欢 提交于 2019-12-08 06:22:46

问题


Intro

I am following this tutorial to learn how to use OpenGL in C#. Everything ran fine until this part: OpenGL 4 with OpenTK in C# Part 5: Buffers and Triangle. I am not using the exact same OpenTK as the one used in the tutorial. I am using this version that is compatible with .NET Core here: https://www.nuget.org/packages/OpenTK.NETCore/

Issue

When I run the program, my console shows the following stacktrace:

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

Code

My code very closely matches the one found on the tutorial:

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);
            }
        }
    }
}

I am very new to OpenGL so I do not understand what this is about. Please help me. Thank you :)


It seems that my problem is related to which version of OpenGL was used. Because I am developping on a laptop with NVIDIA Optimus, it was choosing to use my Intel HD Graphics 4600 which only has OpenGL 4.3, while the OpenGL function used is part of OpenGL 4.5.

What I did was force Optimus to launch all applications using the NVIDIA GPU which support OpenGL 4.5. Now my program launches with no problems.

My question now is:

  1. Is there a way to programmatically force Optimus to use NVIDIA GPU instead of Intel's? If so, how can I keep my program cross-platform?
  2. Is there a way to do what I am trying to do here using an older version of OpenGL? Not everybody has OpenGL 4.5 I believe

来源:https://stackoverflow.com/questions/45675439/opentk-core-gl-namedbufferstorage-raises-system-accessviolationexception

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!