问题
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:
- 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?
- 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