Endless wait for GL3PlusStagingBuffer::wait

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Nucleartree
Kobold
Posts: 37
Joined: Tue Apr 04, 2017 9:10 pm
Location: Cardiff, UK
x 19

Endless wait for GL3PlusStagingBuffer::wait

Post by Nucleartree »

Hi everyone. I'm dealing with an issue at the moment which occurs specifically on Windows when using the OpenGL3 renderer. When I shut my project down with Ogre::Root::shutdown I get an endless wait in the GL3PlusStagingBuffer::wait function, as it looks like Ogre's waiting for OpenGL to confirm buffers have been destroyed. I've narrowed this down to my custom voxeliser which produces meshes from voxel data, for example

Code: Select all

    Ogre::MeshPtr RegionBufferEntry::generateMesh(const std::string& meshName, AV::uint32 width, AV::uint32 height, int maxAltitude){
        if(mNumActiveVox == 0){
            Ogre::MeshPtr out;
            out.reset();
            return out;
        }
        std::string totalName = meshName;
        totalName += "-region";
        totalName += std::to_string((int)mId);
        Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(totalName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
        Ogre::SubMesh* subMesh = mesh->createSubMesh();


    AV::uint32 vertBlocks = mNumVerts / 4;
    //TODO properly set the indice stride to either be 16 or 32 bit.
    static const size_t indiceStride = 4;
    void* indices = OGRE_MALLOC_SIMD(static_cast<size_t>(vertBlocks * 6 * indiceStride), Ogre::MEMCATEGORY_GEOMETRY);
    AV::uint32* indicesPtr = static_cast<AV::uint32*>(indices);
    //size_t indiceStride = (vertBlocks * 6 * 4) + 4 >= 0xFFFF ? 4 : 2;
    for(AV::uint32 i = 0; i < vertBlocks; i++){
        AV::uint32 currIndex = i * 4;
        *(indicesPtr++) = currIndex + 0;
        *(indicesPtr++) = currIndex + 1;
        *(indicesPtr++) = currIndex + 2;
        *(indicesPtr++) = currIndex + 2;
        *(indicesPtr++) = currIndex + 3;
        *(indicesPtr++) = currIndex + 0;
    }

    Ogre::VertexBufferPacked *vertexBuffer = 0;
    Ogre::RenderSystem *renderSystem = Ogre::Root::getSingletonPtr()->getRenderSystem();
    Ogre::VaoManager *vaoManager = renderSystem->getVaoManager();
    try{
        vertexBuffer = vaoManager->createVertexBuffer(elemVec, mNumVerts, Ogre::BT_DEFAULT, mVerts, true);
    }catch(Ogre::Exception &e){
        vertexBuffer = 0;
    }

    Ogre::IndexBufferPacked* indexBuffer = vaoManager->createIndexBuffer(Ogre::IndexType::IT_32BIT, vertBlocks * 6, Ogre::BT_IMMUTABLE, indices, false);

    Ogre::VertexBufferPackedVec vertexBuffers;
    vertexBuffers.push_back(vertexBuffer);
    Ogre::VertexArrayObject* arrayObj = vaoManager->createVertexArrayObject(vertexBuffers, indexBuffer, Ogre::OT_TRIANGLE_LIST);

    subMesh->mVao[Ogre::VpNormal].push_back(arrayObj);
    subMesh->mVao[Ogre::VpShadow].push_back(arrayObj);

    const Ogre::Vector3 halfBounds((mMaxX - mMinX) / 2, -(mMaxY - mMinY) / 2, maxAltitude/2);
    const Ogre::Aabb bounds(halfBounds, halfBounds);
    mesh->_setBounds(bounds);
    mesh->_setBoundingSphereRadius(bounds.getRadius());

    subMesh->setMaterialName("baseVoxelMaterial");

    return mesh;
}

The full code is here https://github.com/OtherMythos/Procedur ... eliser.cpp

I've found that if I never create the custom mesh this hang does not happen. I'm using Ogre-next 3.0 and Windows 10. I've also found this does not occur when using the Vulkan render system. Would anyone be able to suggest anything I could check for this? Thanks.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5514
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1380

Re: Endless wait for GL3PlusStagingBuffer::wait

Post by dark_sylinc »

Hi!

A callstack would be nice as it might hold a clue on what's wrong.

Taking shots in the dark, the problems could be:

  1. OpenGL already shutdown, and wait() happens afterwards.
  2. Main Window was destroyed. OpenGL is tied to the "main" window (usually the first one to be created). Since it already got destroyed, it's the same as shutting down OpenGL and the wait() will never complete.
  3. OpenGL driver bug (has happened in the past, specially with drivers from around 2013-2015; if your GPU is old. However since you say it doesn't happen in Vulkan, I assume you have a relatively recent GPU/driver).
  4. Possible missing call to glFlush().
Nucleartree
Kobold
Posts: 37
Joined: Tue Apr 04, 2017 9:10 pm
Location: Cardiff, UK
x 19

Re: Endless wait for GL3PlusStagingBuffer::wait

Post by Nucleartree »

Hi Dark_synlinc, Here's the callstack from the same Windows 10 machine.

Code: Select all

 	RenderSystem_GL3Plus_d.dll!Ogre::GL3PlusStagingBuffer::wait(__GLsync * syncObj) Line 116	C++
 	RenderSystem_GL3Plus_d.dll!Ogre::GL3PlusStagingBuffer::~GL3PlusStagingBuffer() Line 56	C++
 	[External Code]
 	OgreMain_d.dll!Ogre::VaoManager::deleteStagingBuffers() Line 116	C++
 	OgreMain_d.dll!Ogre::VaoManager::~VaoManager() Line 91	C++
 	RenderSystem_GL3Plus_d.dll!Ogre::GL3PlusVaoManager::~GL3PlusVaoManager() Line 251	C++
 	[External Code]
 	OgreMain_d.dll!Ogre::RenderSystem::shutdown() Line 838	C++
 	RenderSystem_GL3Plus_d.dll!Ogre::GL3PlusRenderSystem::shutdown() Line 698	C++
 	RenderSystem_GL3Plus_d.dll!Ogre::GL3PlusRenderSystem::~GL3PlusRenderSystem() Line 218	C++
 	[External Code]
 	RenderSystem_GL3Plus_d.dll!Ogre::GL3PlusPlugin::uninstall() Line 61	C++
 	OgreMain_d.dll!Ogre::Root::uninstallPlugin(Ogre::Plugin * plugin) Line 1449	C++
 	RenderSystem_GL3Plus_d.dll!dllStopPlugin() Line 48	C++
 	OgreMain_d.dll!Ogre::Root::unloadPlugins() Line 1257	C++
 	OgreMain_d.dll!Ogre::Root::~Root() Line 398	C++
 	[External Code]
 	avCore.dll!AV::Base::shutdown() Line 318	C++
 	av.exe!main(int argc, char * * argv) Line 75	C++
 	[External Code]

I've found this happens for both debug and release builds. I tried things like trying to capture the shutdown with renderdoc but couldn't manage to do it on shutdown. I shut my window down before Ogre is shutdown, although I did try shuffling some of this around with no change to the wait problem. So for instance shutting the sdl2 window down after ogre root has been destroyed and saw no difference. I see this problem on every windows machine I have (tested on intel, nvidia and amd gpus), regardless of age so don't think it's a driver problem. I've found specifically the line that causes the hang to trigger is the line which creates the vbo

Code: Select all

    try{
        vertexBuffer = vaoManager->createVertexBuffer(elemVec, mNumVerts, Ogre::BT_DEFAULT, mVerts, true);
    }catch(Ogre::Exception &e){
        vertexBuffer = 0;
    }

As long as this has happened at some point the wait occurs. If you're happy to run an exe from github this release triggers the problem https://github.com/OtherMythos/Procedur ... ag/v0.10.0 If you start the game up and close it in the menu it closes cleanly, but if you go through to gameplay to the point where the terrain is generated, then close the game it should hang when trying to uninstall gl3+. I'm not sure if there's an easy way to debug this though, although perhapse inserting glFlush or whatever into the .dll and then replacing the one in the distribution?

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5514
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1380

Re: Endless wait for GL3PlusStagingBuffer::wait

Post by dark_sylinc »

Here's the problem.

The SDL2 window is closed and then Ogre Root is destroyed. Invert the order.
And make sure SDL2Window::close is not entered earlier by some other code too place a breakpoint or a fprintf(stderr, "here\n") to be certain.

I've found specifically the line that causes the hang to trigger is the line which creates the vbo

OgreNext creates multiple staging buffers to upload from CPU to GPU, so another routine would eventually cause it.

So for instance shutting the sdl2 window down after ogre root has been destroyed and saw no difference.

Mmmm...
Perhaps the problem appears as soon as you see SDL_QUIT?

One awful workaround is that if you sleep and call vaoManager->_update() in a loop as soon as you see SDL_QUIT, OgreNext will eventually clear all StagingBuffers. The default makes it take 5 minutes; so you'd have to sleep for 5 minutes. You can control this with vaoManager->setDefaultStagingBufferlifetime() to make it expire faster.

Another possible, much better, workaround is to create a dummy 4x4 window and hide it. THEN create your SDL2 window. That way the main window becomes the 4x4 window, and you can better control when it is destroyed. See example.

Nucleartree
Kobold
Posts: 37
Joined: Tue Apr 04, 2017 9:10 pm
Location: Cardiff, UK
x 19

Re: Endless wait for GL3PlusStagingBuffer::wait

Post by Nucleartree »

Hmmm, well that's interesting because I thought I tried that, but actually yes it looks like that fixed it! Thanks very much :D