简体   繁体   English

写入索引缓冲区时崩溃

[英]Crash when writing to an index buffer

I'm currently writing an engine using C++11/SDL2/OpenGL for Windows, Mac and Linux. 我目前正在为Windows,Mac和Linux使用C ++ 11 / SDL2 / OpenGL编写引擎

It runs fine on Mac and Linux, but I'm getting a nasty crash on my Windows+Nvidia desktop (The only other Windows environment I have is a virtual machine, which doesn't support my OpenGL feature set) 它可以在Mac和Linux上正常运行,但在Windows + Nvidia桌面上却遇到了令人讨厌的崩溃(我拥有的唯一其他Windows环境是虚拟机,它不支持我的OpenGL功能集)

I've had two friends test it on different Windows+AMD devices, so my issue seems to be related to Nvidia's drivers and the current state I have them in, meaning an SSCCE probably will not help. 我有两个朋友在不同的Windows + AMD设备上对其进行测试,因此我的问题似乎与Nvidia的驱动程序以及我所处的当前状态有关,这意味着SSCCE可能无济于事。
Vertex buffers are created fine, and the creation of the following index buffer used to work fine at some unknown point in time. 顶点缓冲区创建的罚款,并使用了下列索引缓冲区的建立在一些未知的时间点很好地工作。 Perhaps before driver updates... 也许在驱动程序更新之前...

For reference, my Buffer class is as follows: 供参考,我的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 );
}

The code to create my index buffer looks like: 创建我的索引缓冲区的代码如下:

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

The crash occurs on glBufferData( type, size, data, GL_STREAM_DRAW ); 崩溃发生在glBufferData( type, size, data, GL_STREAM_DRAW );
id is 4 id是4
type is 34963 aka GL_ELEMENT_ARRAY_BUFFER type是34963,也就是GL_ELEMENT_ARRAY_BUFFER
size is 12 size是12
data is quadIndices data为quadIndices

If I try to create the index buffer without filling it, then mapping it and writing to it like so: 如果我尝试在不填充索引缓冲区的情况下创建索引缓冲区,则将其映射并像这样写入:

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();

then the crash occurs on glMapBufferRange inside Buffer::MapDiscard 然后上发生崩溃glMapBufferRange内部Buffer::MapDiscard

The rationale behind that mapping method is because trying to map a buffer that is busy can introduce busy-waits. 该映射方法背后的原理是因为尝试映射一个繁忙的缓冲区会引入繁忙等待。

// 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.

I've tried searching around for answers, but the only solutions I've found are related to passing incorrect sizes, or wrong order of arguments for glBufferData. 我尝试搜索答案,但是找到的唯一解决方案与传递错误的大小或glBufferData的参数顺序错误有关。 Not helpful. 没有帮助。

It seems that by disabling GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB the crash no longer manifests itself and my program's behaviour is correct. 似乎通过禁用GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB ,崩溃不再显示出来,并且我的程序的行为是正确的。

I guess I was right in assuming it's a driver bug. 我猜我认为这是驱动程序错误是正确的。 I'll try forwarding it onto the dev team. 我将尝试将其转发给开发团队。

For reference, this is targeting OpenGL 3.1 on an Nvidia GTX 680 driver version 350.12 作为参考,这是针对Nvidia GTX 680驱动程序版本350.12上的OpenGL 3.1。
glewExperimental is enabled, and the following OpenGL context flags are set: core profile, forward compatible, debug 启用glewExperimental,并设置以下OpenGL上下文标志:核心配置文件,前向兼容,调试

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM