[2.2] Terra samplerblock error

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


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

[2.2] Terra samplerblock error

Post by Nucleartree »

Hi everyone.

I've been porting my project to Ogre 2.2 recently and one of the problems I ran into was with Terra. My code was running into an assertion in the HlmsManager:

Code: Select all

        if( &mSamplerblocks[samplerblock->mId] != samplerblock )
        {
            OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND,
                         "The Samplerblock wasn't created with this manager!",
                         "HlmsManager::destroySamplerblock" );
        }
However, on further inspection I feel like this particular part of the code is at fault:

OgreHlmsTerraDatablock.cpp:85 (in the datablock's destructor)

Code: Select all

        HlmsManager *hlmsManager = mCreator->getHlmsManager();
        if( hlmsManager )
        {
            for( size_t i=0; i<NUM_TERRA_TEXTURE_TYPES; ++i )
            {
                if( mSamplerblocks[i] )
                    hlmsManager->destroySamplerblock( mSamplerblocks[i] );
            }
        }
In 2.1 the datablock stored an array of samplerblocks and deleted them on shutdown. In 2.2 some of this logic was moved to OgreHlmsTextureBaseClass.inl. This also contains a destructor which does a very similar thing:

OgreHlmsTextureBaseClass.inl:58

Code: Select all

            for( size_t i=0; i<OGRE_HLMS_TEXTURE_BASE_MAX_TEX; ++i )
            {
                if( mSamplerblocks[i] )
                    hlmsManager->destroySamplerblock( mSamplerblocks[i] );
            }
My debugger is showing that both of these loops are run on datablock destruction, which means the call to destroy the sampler blocks happens twice. The assertion is met because during the second loop it tries to destroy a samplerblock which has already been destroyed. Furthermore, this doesn't appear in the official sample because, according to gdb, the check for the hlmsManager returns false so the loop is never run. This is most likely because the terrain is being destroyed on shutdown. My project is creating terrains on the fly during runtime.

My fix for this problem was just to remove the loop in the terraDatablock's destructor. I'd be interested to know if anyone else thinks this is an actual bug or not. This is as of commit 1761d69.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5502
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1370

Re: [2.2] Terra samplerblock error

Post by dark_sylinc »

Hi!

Aside from a possible memory corruption somewhere else or other weird reasons, the main cause of the error are:
  1. The samplerblock was created programmatically via _setTexture, but incorrectly:

    Code: Select all

    // Correct
    HlmsSamplerblock samplerBlockRef;
    datablock->setTexture( textureType, texture, &samplerBlockRef );
    
    // Correct
    HlmsSamplerblock samplerBlockRef;
    HlmsSamplerblock *ptr = mHlmsManager->getSamplerblock( samplerBlockRef );
    datablock->_setTexture( textureType, texture, ptr );
    
    // Incorrect
    HlmsSamplerblock samplerBlockRef;
    datablock->_setTexture( textureType, texture, &samplerBlockRef );
  2. Terra is being destroyed too late, i.e. after Ogre::Root or at least the HlmsManager has already been shutdown
  3. mHlmsManager->getSamplerblock or mHlmsManager->addReference got called so many times on the same samplerblock (without calling destroySamplerblock) that the reference count overflowed
Try a debug build to see if an assert triggers.

Cheers
Matias