在 std::thread 中使用 SOIL 加载 OpenGL 纹理会引发 "Integer Division by Zero"
Loading OpenGL texture with SOIL in std::thread raises "Integer Division by Zero"
我可以在 SOIL/OpenGL 中正常加载纹理。没有错误,一切正常:
// this is inside my texture loading code in my texture class
// that i normally use for loading textures
image = SOIL_load_OGL_texture
(
file,
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
NULL
);
但是,使用相同的代码并从 std::thread 调用它,在行 image = SOIL_load_OGL_texture
我得到未处理的异常 Integer Division by Zero
:
void loadMe() {
Texture* abc = new Texture("res/img/office.png");
}
void loadStuff() {
Texture* loading = new Texture("res/img/head.png"); // < always works
loadMe() // < always works
std::thread textures(loadMe); // < always "integer division by zero"
这是我的纹理 class 中的一些相关代码:
// inside the class
private:
GLint w, h;
GLuint image;
// loading the texture (called by constructor if filename is given)
void Texture::loadImage(const char* file)
{
image = SOIL_load_OGL_texture
(
file,
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
NULL
);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
glBindTexture(GL_TEXTURE_2D, 0);
if (image <= 0)
std::cout << file << " failed to load!\n";
else
std::cout << file << " loaded.\n";
glDisable(GL_TEXTURE_2D);
}
它恰好在 image = SOIL_load_OGL_texture
引发异常,当我进入调试器时,我看到 w = -816294792
和 w = -816294792
之类的东西,但我想这只是意味着它没有尚未设置,因为它还显示在用于加载其他纹理的调试器中。
此外,代码的 SOIL_load_OGL_texture 部分在纹理 class 之外本身工作正常,即使在 std::thread.
中也是如此
知道这里发生了什么吗?
你就是这样做的。请注意,正如其他人在评论中提到的那样,需要为使用 GL 的每个线程保持当前上下文。这意味着实际上不能在不使一个线程成为 GL 上下文所有者的情况下在多个线程中进行 GL API 调用。因此,如果打算分离图像加载开销,建议在单独的线程中使用库将图像文件加载到缓冲区中,然后在主线程中将该缓冲区用于 glTexImage2D。直到图像加载完毕,才能显示虚拟纹理。
我试过检查你在哪个平台上(见上面的评论),因为我没有看到回应,我假设下面是 Linux。
/* Regular GL context creation foo */
/* Regular attribute, uniform, shader creation foo */
/* Create a thread that does loading with SOIL in function SOIL_loader */
std::thread textureloader(SOIL_loader);
/* Wait for loader thread to finish,
thus defeating the purpose of a thread. Ideally,
only the image file read/decode should happen in separate thread */
textureloader.join();
/* Make the GL context current back again in the main thread
for other actions */
glfwMakeContextCurrent((GLFWwindow*)window);
/* Some other foo */
======
这是加载程序线程函数:
void SOIL_loader()
{
glfwMakeContextCurrent((GLFWwindow*)window);
SOIL_load_OGL_texture
(
"./img_test.png",
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID /* or passed ID */,
NULL
);
GL_CHECK(SOIL);
}
在 Ubuntu 14.04、Mesa 和 glfw3 上测试。
我可以在 SOIL/OpenGL 中正常加载纹理。没有错误,一切正常:
// this is inside my texture loading code in my texture class
// that i normally use for loading textures
image = SOIL_load_OGL_texture
(
file,
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
NULL
);
但是,使用相同的代码并从 std::thread 调用它,在行 image = SOIL_load_OGL_texture
我得到未处理的异常 Integer Division by Zero
:
void loadMe() {
Texture* abc = new Texture("res/img/office.png");
}
void loadStuff() {
Texture* loading = new Texture("res/img/head.png"); // < always works
loadMe() // < always works
std::thread textures(loadMe); // < always "integer division by zero"
这是我的纹理 class 中的一些相关代码:
// inside the class
private:
GLint w, h;
GLuint image;
// loading the texture (called by constructor if filename is given)
void Texture::loadImage(const char* file)
{
image = SOIL_load_OGL_texture
(
file,
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
NULL
);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
glBindTexture(GL_TEXTURE_2D, 0);
if (image <= 0)
std::cout << file << " failed to load!\n";
else
std::cout << file << " loaded.\n";
glDisable(GL_TEXTURE_2D);
}
它恰好在 image = SOIL_load_OGL_texture
引发异常,当我进入调试器时,我看到 w = -816294792
和 w = -816294792
之类的东西,但我想这只是意味着它没有尚未设置,因为它还显示在用于加载其他纹理的调试器中。
此外,代码的 SOIL_load_OGL_texture 部分在纹理 class 之外本身工作正常,即使在 std::thread.
中也是如此知道这里发生了什么吗?
你就是这样做的。请注意,正如其他人在评论中提到的那样,需要为使用 GL 的每个线程保持当前上下文。这意味着实际上不能在不使一个线程成为 GL 上下文所有者的情况下在多个线程中进行 GL API 调用。因此,如果打算分离图像加载开销,建议在单独的线程中使用库将图像文件加载到缓冲区中,然后在主线程中将该缓冲区用于 glTexImage2D。直到图像加载完毕,才能显示虚拟纹理。
我试过检查你在哪个平台上(见上面的评论),因为我没有看到回应,我假设下面是 Linux。
/* Regular GL context creation foo */
/* Regular attribute, uniform, shader creation foo */
/* Create a thread that does loading with SOIL in function SOIL_loader */
std::thread textureloader(SOIL_loader);
/* Wait for loader thread to finish,
thus defeating the purpose of a thread. Ideally,
only the image file read/decode should happen in separate thread */
textureloader.join();
/* Make the GL context current back again in the main thread
for other actions */
glfwMakeContextCurrent((GLFWwindow*)window);
/* Some other foo */
======
这是加载程序线程函数:
void SOIL_loader()
{
glfwMakeContextCurrent((GLFWwindow*)window);
SOIL_load_OGL_texture
(
"./img_test.png",
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID /* or passed ID */,
NULL
);
GL_CHECK(SOIL);
}
在 Ubuntu 14.04、Mesa 和 glfw3 上测试。