我还将在加载每个图像或纹理后立即使用 OpenGL glBindtexture() 执行绑定,这样我只需要在每个 SceneObject 实例中保存纹理 ID。当我试图在工作线程中执行加载时,整个程序就会崩溃。
OpenGL 上下文一次只能在一个线程中处于活动状态。一般来说,多线程 OpenGL 操作通常会成为一场噩梦,要正确处理。在您的情况下,您打算做的是委派资源加载。在过去,在缓冲区对象出现之前,您可以通过创建辅助上下文并与主上下文共享其“列表”来完成此操作。
今天我们有更好的东西:缓冲对象。缓冲区对象允许您以异步方式向 OpenGL 发送数据。它像这样
glGenBuffers(...);
glBindBuffer(...);
glBufferData(..., size, usage);
void *p = glMapBuffer(...);
memcpy(p, data, size);
glUnmapBuffer(...);
glTexImage / glDrawPixels / etc.
要理解的重要部分是,glMapBuffer 分配的地址空间是跨线程共享的。因此,您可以告诉主线程中的 OpenGL 上下文映射一个缓冲区对象,向您的工作线程发送信号,并进行分配。然后工作线程填充数据并在完成后向 OpenGL 上下文线程发送信号以取消映射。
编辑多线程
所以要做到这一点,你需要在两边实现一些信号处理程序(伪代码)
signal OpenGLThread::mapPixelBufferObjectForWrite(ImageLoader il):
glGenBuffers(1, &self.bufferId)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, self.bufferId)
glBufferData(GL_PIXEL_UNPACK_BUFFER, il.unpackedImageSize, NULL, GL_STATIC_DRAW)
BufferObjectMapping map(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY))
send_signal(target_thread = workerthread, target_signal_handler = workerthread::loadImageToBuffer(map, il), signal_on_finish = self.unmapPixelBufferObjectWriteFinishedGenTexture(map))
signal IOThread::loadImageToBuffer(BufferObjectMapping map, ImageLoader il):
/* ... */
signal OpenGLThread::unmapPixelBufferObjectWriteFinishedGenTexture(BufferObjectMapping map, ImageLoader il):
if(map.mapping_target == GL_PIXEL_UNPACK_BUFFER)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, self.bufferId)
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER)
glGenTextures(1, &il.textureId)
glBindTexture(il.target, il.textureId)
for mipmaplevel in il.levels
glTexImage2D(il.target, mipmaplevel, il.internalformat, il.width, il.height, il.border, il.format, il.type, mipmaplevel.offset)