OpenTK.Core - GL.NamedBufferStorage вызывает System.AccessViolationException
вступление
Я следую этому руководству, чтобы узнать, как использовать OpenGL в C#. До этой части все работало нормально: OpenGL 4 с OpenTK в C# Часть 5: Буферы и треугольник. Я не использую тот же 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, он решил использовать мою Intel HD Graphics 4600, которая имеет только OpenGL 4.3, тогда как используемая функция OpenGL является частью OpenGL 4.5.
Я заставил Optimus запустить все приложения, используя графический процессор NVIDIA, поддерживающий OpenGL 4.5. Теперь моя программа запускается без проблем.
Мой вопрос сейчас:
- Есть ли способ принудительно заставить Optimus использовать графический процессор NVIDIA вместо Intel? Если так, как я могу сохранить свою программу кроссплатформенной?
- Есть ли способ сделать то, что я пытаюсь сделать здесь, используя более старую версию OpenGL? Я думаю, что не у всех есть OpenGL 4.5