与Marshal.GetDelegateForFunctionPointer一起使用时,WGL / OpenGL函数的作用不一致

时间:2016-04-09 21:10:02

标签: c# opengl pinvoke

我在C#中编写了一些基本的OpenGL3代码,其中有许多(可怕的)pinvokes。 OpenGL3需要通过OpenGL32.wglGetProcAddress将某些扩展函数(例如wglCreateContextAttribsARB)加载到IntPtr中。为了在C#中使用它们,我需要使用Marshal.GetDelegateForFunctionPointer将函数指针转换为委托。

我想保存我已经加载的函数(因为其中一些被定期使用),并试图通过保留委托的副本来做到这一点(我也存储IntPtrs以防它们变得垃圾收集)。

但是,在某些计算机上(不一致,有时从Visual Studio运行但运行.exe不运行...),wglCreateContextAttribsARB以这种方式保存时返回IntPtr.Zero。但是,如果我在调用函数时,在每次调用期间使用Marshal.GetDelegateForFunctionPointer将函数指针转换为委托,它工作正常......

为什么会这样,并且在每次通话期间进行转换都有开销?请记住,在渲染调用期间会使用其中一些调用,这些调用可能有许多操作(每个基元一个)。

渲染上下文创建代码:

int[] attribs = { (int)ArbCreateContext.MajorVersion, major, (int)ArbCreateContext.MinorVersion, minor, (int)ArbCreateContext.ContextFlags, 0 };

//create temp context to be able to call wglGetProcAddress
IntPtr tempContext = OpenGL32.wglCreateContext(DeviceContext);
if (tempContext == IntPtr.Zero)
    throw new Exception("tempContext failed to create.");
if (!OpenGL32.wglMakeCurrent(DeviceContext, tempContext))
    throw new Exception("wglMakeCurrent Failed");

OpenGL32.LoadWGLExtensions();

RenderContext = OpenGL32.wglCreateContextAttribsARB(DeviceContext, IntPtr.Zero, attribs);
if (RenderContext == IntPtr.Zero)
    throw new HaighException("Something went wrong with wglCreateContextAttribsARB: {0}", Marshal.GetLastWin32Error());

在上面的代码中调用wglCreateContextAttribsARB的代码有时会导致最后的异常:

private static Dictionary<string, IntPtr> _entryPoints = new Dictionary<string, IntPtr>(); 

private delegate IntPtr DEL_wglCreateContextAttribsARB(IntPtr hDc, IntPtr sharedContext, int[] attribList);
private static DEL_wglCreateContextAttribsARB _wglCreateContextAttribsARB;

public static void LoadWGLExtensions()
{
    IntPtr procAddress;
    //get the handle to the WGL extension function pointer we need
    procAddress = OpenGL32.wglGetProcAddress("wglCreateContextAttribsARB");
    if (procAddress == IntPtr.Zero)
        throw new Exception("something went wrong with wglGetProcAddress");
    //convert intptr to delegate and save the function
    _wglCreateContextAttribsARB = (DEL_wglCreateContextAttribsARB)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(DEL_wglCreateContextAttribsARB));
    //store the IntPtr just in case...
    _entryPoints.Add("wglCreateContextAttribsARB", procAddress);
}

public static IntPtr wglCreateContextAttribsARB(IntPtr hDc, IntPtr sharedContext, int[] attribList)
{
    return _wglCreateContextAttribsARB(hDc, sharedContext, attribList);
}

调用wglCreateContextAttribsARB始终有效的代码:

private static Dictionary<string, IntPtr> _entryPoints = new Dictionary<string, IntPtr>(); 

private delegate IntPtr DEL_wglCreateContextAttribsARB(IntPtr hDc, IntPtr sharedContext, int[] attribList);

public static void LoadWGLExtensions()
{
    IntPtr procAddress;
    //get the handle to the WGL extension function pointer we need
    procAddress = OpenGL32.wglGetProcAddress("wglCreateContextAttribsARB");
    if (procAddress == IntPtr.Zero)
    throw new Exception("something went wrong with wglGetProcAddress");
    //convert intptr to delegate and save the function
    _wglCreateContextAttribsARB = (DEL_wglCreateContextAttribsARB)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(DEL_wglCreateContextAttribsARB));
    //store the IntPtr just in case...
    _entryPoints.Add("wglCreateContextAttribsARB", procAddress);
}

public static IntPtr wglCreateContextAttribsARB(IntPtr hDc, IntPtr sharedContext, int[] attribList)
{
    return ((DEL_wglCreateContextAttribsARB)Marshal.GetDelegateForFunctionPointer(_entryPoints["wglCreateContextAttribsARB"], typeof(DEL_wglCreateContextAttribsARB)))(hDc, sharedContext, attribList);
}

1 个答案:

答案 0 :(得分:1)

使用chrome.runtime.onMessage.addListener(function(msg) { console.log(msg.urls) chrome.tabs.create({url: msg.urls[i]}); }) 获得的函数指针与相应的OpenGL上下文相关联。因此,当您存储指针时,必须将它们与从中获取的OpenGL上下文一起存储。基本上你需要一个从一对background-image: url("http://i.imgur.com/7h8ejPJ.png")映射的字典。

在没有相应的OpenGL上下文激活的情况下调用OpenGL函数指针会导致WGL中出现未定义的行为。