As Stefan Hanke as alreadt said,you not。
当你可以拨打glDeleteTextures
?在创建底层纹理的OpenGL上下文(或更确切地说,它sharesobject name space)在调用线程上是当前的。终结器(类的析构函数)正在运行GC线程,但实际上我不知道它是否指定了GC如何执行(它是.NET JIT的可响应性);我认为最明显的实现是一个独立的线程。事实上,在终结器中调用glDeleteTextures
并不是一个好主意,因为您不知道在该线程上OpenGL上下文是否是当前的。
实现IDisposable
可能是一个想法,但问题仍然存在,因为Dispose实现必须知道OpenGL上下文是否真的是最新的。为此,您可以使用平台相关例程,如wglGetCurrentContext。
我遇到了同样的问题,我最终选择了以下解决方案。
上下文抽象(RenderContext),它将OpenGL上下文与一个线程进行映射。下面是MakeCurrent实现:
public void MakeCurrent(IDeviceContext deviceContext, bool flag)
{
if (deviceContext == null)
throw new ArgumentNullException("deviceContext");
if (mDeviceContext == null)
throw new ObjectDisposedException("no context associated with this RenderContext");
int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
if (flag) {
// Make this context current on device
if (Gl.MakeContextCurrent(deviceContext, mRenderContext) == false)
throw new InvalidOperationException("context cannot be current because error " + Marshal.GetLastWin32Error());
// Cache current device context
mCurrentDeviceContext = deviceContext;
// Set current context on this thread (only on success)
lock (sRenderThreadsLock) {
sRenderThreads[threadId] = this;
}
} else {
// Make this context uncurrent on device
bool res = Gl.MakeContextCurrent(deviceContext, mRenderContext);
// Reset current context on this thread (even on error)
lock (sRenderThreadsLock) {
sRenderThreads[threadId] = null;
}
if (res == false)
throw new InvalidOperationException("context cannot be uncurrent because error " + Marshal.GetLastWin32Error());
}
}
public static RenderContext GetCurrentContext()
{
int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
lock (sRenderThreadsLock) {
RenderContext currentThreadContext;
if (sRenderThreads.TryGetValue(threadId, out currentThreadContext) == false)
return (null);
return (currentThreadContext);
}
}
private static readonly object sRenderThreadsLock = new object();
private static readonly Dictionary<int, RenderContext> sRenderThreads = new Dictionary<int,RenderContext>();
如果(且仅当)使用MakeCurrent方法所执行的上下文货币,RenderContext中类可以知道它是否是当前的调用线程。总之,Dispose的实现可以使用RenderContext类来真正删除OpenGL对象。
但是,如果调用线程没有OpenGL上下文,那该怎么办?我已经通过引入一个GraphicGarbageCollector来解决这个问题,它收集在适当的线程中(当正确的OpenGL上下文是当前的)时被释放的资源列表(纹理名称,...)。
本质上,每个资源都有一个对象名称空间(OpenGL上下文共享列表;我已经使用GUID进行了定义)。使用对象名称空间,资源实例可以获得合适的GraphicGarbageCollector,排列资源名称(例如纹理ID);在更合适的情况下,使用基础上下文释放入队资源。
相同的机制可以与参考系统一起使用:当引用计数达到0时,它会处理资源并将其收集以进行垃圾回收。这是一个一致的实现:你可以找到我的here。
不需要再次回答,还有两个选项:1.使用UI'SynchronizationContext'来安排OpenGL线程的删除。 2.用'wglShareLists'创建一个辅助上下文,其唯一目的是发布OpenGL句柄。我不认为有一个解决方案不会让你畏缩...... – 2012-04-29 12:01:06