【问题标题】:OpenGL crash just by removing std::cout<<"hi"<<std::endl from the programOpenGL 崩溃只需从程序中删除 std::cout<<"hi"<<std::endl
【发布时间】:2016-07-14 22:29:39
【问题描述】:

我发现了一个非常神秘的问题,我将我在程序中的调试行和程序“段错误(核心转储)”注释out

我缩小了程序范围并得出了这个结论。这是重现问题的全部代码:

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <highgui.h>
#include <GL/glut.h>
#include <iostream>

int main(int argc, char **argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA | GLUT_ALPHA | GLUT_DEPTH | GLUT_DOUBLE);
  glutInitWindowSize(500, 281);
  (void) glutCreateWindow("Alpha Test");

  cv::Mat image = cv::imread("alphatest.png");
  int texWidth = image.cols;
  int texHeight = image.rows;
  GLuint texId;
  glGenTextures(1, &texId);
  glBindTexture(GL_TEXTURE_2D, texId);

  //std::cout << "hi" << std::endl;

  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, image.ptr());
}

此程序在glTexImage2D 崩溃并显示错误消息:

zsh: segmentation fault (core dumped)  ./mystery

(该程序已被命名为神秘)

通过取消注释cout 行,程序运行良好,没有错误以及消息“hi”。我想知道为什么我必须保留调试线?

这是 alphatest.png

【问题讨论】:

  • glut 初始化之后,您应该创建有效的渲染opengl 上下文并在任何gl 调用之前通过调用glewInit() 来初始化glew 函数指针。
  • @ampawd:glTexImage2D 是过去的一个函数。它自 OpenGL-1.0 以来一直存在。它当然不需要 GLEW。
  • @datenwolf 是的,但在他调用一些现代 gl 函数之前 glGenTexture glBindTexture 这需要 glew 初始化才能正常工作。
  • @ampawd:那是错误的。纹理是在 OpenGL 1.1 中引入的,并且(至少在 Windows 上)可以直接从 opengl 实现中获得。
  • @ampawd:OP 调用的函数都不是现代 OpenGL 函数。此外,GLEW 并不是唯一的扩展加载器,据我们所知,OP 很可能会使用加载器包装库来代替 libGLopengl32 链接,并且透明地加载所有扩展。该问题显然与未初始化 OpenGL 或未能加载扩展指针无关。由于image 的内存布局与 OpenGL 尝试从中读取的内容不匹配,很可能是未对齐的读取访问或缓冲区溢出。

标签: c++ opengl glut


【解决方案1】:

您的图像行对齐很可能不符合 OpenGL 读取图像的默认设置(4 字节行对齐)。这可能会导致 OpenGL 从未映射的页面读取,从而导致段错误。在执行可能创建页面分配的 iostream 输出时,与图像缓冲区相邻,因此此问题仍然“隐藏”。

测试一下:

glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);  /* tightly packed*/
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); /* tightly packed*/
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);   /* tightly packed*/
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);   /* tightly aligned*/
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, image.ptr());

此外,如果您的图像是灰度图像,那么读取 GL_BGRA 格式将需要比 imread 提供的更多数据。您不应该对这些参数进行硬编码,而是在 imread 返回时从图像文件中确定它们。

【讨论】:

  • 这是真的!我的图像只有一个通道,所以读取错误。并感谢 iostream 的解释!
猜你喜欢
  • 1970-01-01
  • 2017-05-13
  • 2020-03-19
  • 1970-01-01
  • 2012-01-08
  • 1970-01-01
  • 2021-08-04
  • 2014-01-04
相关资源
最近更新 更多