【问题标题】:OpenGL glMultiDrawElements crashes on index offset vectorOpenGL glMultiDrawElements 在索引偏移向量上崩溃
【发布时间】:2014-12-12 11:07:08
【问题描述】:

我很难为这个问题想出一个好标题,所以如果你能想出一个好标题,请提出一个新标题。也许我们可以在解决我的问题后做......现在开始:

我目前正在移植代码以使用 glMultiDrawElements,而不是多次调用 glDrawElements。为此,我使用了我称之为 sequenceList 的东西,它只是两个向量的 std::pair,一个 unsigned int 和一个 int。

  // Sequence of vectors defining < StartIndex per primitive, Number of vertices per primitive >
  using SequenceList = std::pair< std::vector< unsigned int >, std::vector< GLsizei > >;

为了能够对所有变体仅使用一个绘制函数(尽管只有一个基元可以使用一个索引列表进行绘制),我将函数调用概括为 always 使用 sequenceList 对象,但只有一个索引值。这意味着我将 glMultiDrawElements 用于所有索引绘制调用(以及 glMultiDrawArrays 用于非索引绘制调用)。

void GLVBOProbe::draw( unsigned startIndex, int numberOfIndicesToDraw ) const
{
  VertexArray::SequenceList sequences = { { startIndex }, { numberOfIndicesToDraw } ) };
  GLVBOLib::the().draw( name_, sequences );
}

然后,绘图调用绑定数组/法线/纹理和索引(如果需要)缓冲区。对 glMultiDrawElements 的调用看起来像

glMultiDrawElements( info.mode, sequences.second.data(), GL_UNSIGNED_INT, (const GLvoid **)sequences.first.data(), (GLsizei)sequences.second.size() );

在我的测试用例中,我从 0 开始渲染 75000 个索引。因此,sequences.second 包含 75000 个值,sequence.first 仅包含一个值:0。

现在问题来了:这会崩溃

First-chance exception at 0x000000004735E56B in Application.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

我尝试了很多不同的方法来查找问题,终于找到了一个不会崩溃的变体,而这个变体让我感到困惑。

如果我将向量复制到一个新的局部变量,它就可以工作。由于向量的大小为 1,因此仅此一点不会有问题,但是对于 3000 个索引偏移量,每帧都执行此操作感觉不那么有趣。

// Non crashing version
std::vector< unsigned int > indicesOffset = sequences.first;
// using sequence and indices
glMultiDrawElements( info.mode, sequences.second.data(), GL_UNSIGNED_INT, (const GLvoid **)indicesOffset.data(), (GLsizei)sequences.second.size() );

我的一个同事说这可能与向量的内存对齐有关,说我必须使用 boost 的 boost::aligned_allocator 才能让它工作。

【问题讨论】:

  • 如果你使用参考? std::vector&lt; unsigned int &gt;&amp; indicesOffset = sequences.first;
  • 这可能与stackoverflow.com/questions/8719287/… 这个问题有关,并且复制向量时它不会崩溃的事实纯属巧合。这只是因为在新创建的向量之后 内存中没有任何内容。我应该有一个 int 指针向量,而不是一个整数向量。
  • 你是 64 位的吗?如果是这样,那么我确实可以看到从unsigned int* 转换为GLVoid** 的问题
  • 是的,我使用的是 64 位。我也认为这是问题所在。

标签: c++ opengl vector


【解决方案1】:

sizeof(GLvoid*) 不保证等于sizeof(unsigned int)。但是,您可以将unsigned int 替换为GLintptr​,它保证与指针大小相同。

【讨论】:

  • 谢谢,GLintptr 也是一种选择:opengl.org/discussion_boards/showthread.php/…
  • 等等.. GLVoid* 必须与 (unsigned int*) 大小相同,指针在平台上的大小始终相同,不是吗?
  • 哦,抱歉,我将您的答案误读为 (unsigned int*) 而不是 (unsigned int)。我的错。
【解决方案2】:

问题似乎是我在 64 位平台上,并且 glMultiDrawArrays 期望 指针指向 ints,而不是实际的 ints。

这里有更多描述。

https://www.opengl.org/discussion_boards/showthread.php/182391-How-to-use-glMultiDrawElements-and-glDrawElements

对此的解决方案是使用GLintptr 作为类型,它描述了数组中的字节偏移。所以数组中的每个位置也必须让它的指针大小乘以自身。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-18
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多