写入索引缓冲区时崩溃

Crash when writing to an index buffer

本文关键字:崩溃 缓冲区 索引      更新时间:2023-10-16

我目前正在为Windows,Mac和Linux编写使用C++11/SDL2/OpenGL的引擎。

它在Mac和Linux上运行良好,但是我的Windows + Nvidia桌面上遇到了令人讨厌的崩溃(我唯一的其他Windows环境是虚拟机,它不支持我的OpenGL功能集)

我有两个朋友在不同的Windows + AMD设备上测试过它,所以我的问题似乎与Nvidia的驱动程序和我所处的当前状态有关,这意味着SSCCE可能无济于事。顶点缓冲区创建
良好,以下索引缓冲区的创建用于在某个未知时间点正常工作。也许在驱动程序更新之前...

作为参考,我的 Buffer 类如下所示:

static GLenum GetGLBufferType( BufferType bufferType ) {
switch ( bufferType ) {
case BufferType::Vertex: {
return GL_ARRAY_BUFFER;
} break;
case BufferType::Index: {
return GL_ELEMENT_ARRAY_BUFFER;
} break;
case BufferType::Uniform: {
return GL_UNIFORM_BUFFER;
} break;
default: {
return GL_NONE;
} break;
}
}
GLuint Buffer::GetID( void ) const {
return id;
}
Buffer::Buffer( BufferType bufferType, const void *data, size_t size )
: type( GetGLBufferType( bufferType ) ), offset( 0 ), size( size )
{
glGenBuffers( 1, &id );
glBindBuffer( type, id );
glBufferData( type, size, data, GL_STREAM_DRAW );
if ( bufferType == BufferType::Uniform ) {
glGetIntegerv( GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, reinterpret_cast<GLint *>( &alignment ) );
}
else {
alignment = 16;
}
}
Buffer::~Buffer() {
glDeleteBuffers( 1, &id );
}
void *Buffer::Map( void ) {
Bind();
return glMapBufferRange( type, 0, size, GL_MAP_WRITE_BIT );
}
BufferMemory Buffer::MapDiscard( size_t allocSize ) {
Bind();
allocSize = (allocSize + alignment - 1) & ~(alignment - 1);
if ( (offset + allocSize) > size ) {
// We've run out of memory. Orphan the buffer and allocate some more memory
glBufferData( type, size, nullptr, GL_STREAM_DRAW );
offset = 0;
}
BufferMemory result;
result.devicePtr = glMapBufferRange(
type,
offset,
allocSize,
GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_RANGE_BIT
);
result.offset = offset;
result.size = allocSize;
offset += allocSize;
return result;
}
void Buffer::Unmap( void ) {
glUnmapBuffer( type );
}
void Buffer::BindRange( int index, size_t rangeOffset, size_t rangeSize ) const {
if ( !rangeSize ) {
rangeSize = size - rangeOffset;
}
glBindBufferRange( type, index, id, rangeOffset, rangeSize );
}
void Buffer::Bind( void ) const {
glBindBuffer( type, id );
}

创建索引缓冲区的代码如下所示:

static const uint16_t quadIndices[6] = { 0, 2, 1, 1, 2, 3 };
quadsIndexBuffer = new Buffer( BufferType::Index, quadIndices, sizeof(quadIndices) );

崩溃发生在glBufferData( type, size, data, GL_STREAM_DRAW );
id是 4
type是 34963 又名GL_ELEMENT_ARRAY_BUFFER
size是 12
data

是四指数如果我尝试在不填充索引缓冲区的情况下创建索引缓冲区,则映射它并写入它,如下所示:

quadsIndexBuffer = new Buffer( BufferType::Index, nullptr, sizeof(quadIndices) );
BufferMemory bufferMem = quadsIndexBuffer->MapDiscard( 6 * sizeof(uint16_t) );
uint16_t *indexBuffer = static_cast<uint16_t *>( bufferMem.devicePtr );
for ( size_t i = 0u; i < 6; i++ ) {
*indexBuffer++ = quadIndices[i];
}
quadsIndexBuffer->Unmap();

然后崩溃发生在glMapBufferRange内部Buffer::MapDiscard

该映射方法背后的基本原理是因为尝试映射繁忙的缓冲区可能会引入繁忙等待。

// Usage strategy is map-discard. In other words, keep appending to the buffer
// until we run out of memory. At this point, orphan the buffer by re-allocating
// a buffer of the same size and access bits.

我尝试四处寻找答案,但我找到的唯一解决方案与传递不正确的大小或glBufferData的参数顺序错误有关。没有帮助。

似乎通过禁用GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB崩溃不再表现出来,我的程序的行为是正确的。

我想我假设这是一个驱动程序错误是正确的。我会尝试将其转发给开发团队。

作为参考,这是针对 Nvidia GTX 680 驱动程序版本 350.12 上的 OpenGL 3.1
启用 glewExperiment,并设置以下 OpenGL 上下文标志:核心配置文件、向前兼容、调试