[Solved] StagingTexture returns zero width/height TextureBox

Problems building or running the engine, queries about how to use features etc.
Post Reply
dermont
Bugbear
Posts: 812
Joined: Thu Dec 09, 2004 2:51 am
x 42

[Solved] StagingTexture returns zero width/height TextureBox

Post by dermont »

I know branch v2-2 is a WIP so I'm not sure it's OK to ask any questions.

Anyway I'm creating a number of video textures with python-ogre v2-2WIP, updating the texture from the main thread.

I'm running into problems where the StagingTexture created via TextureGpuManager::getStagingTexture has the same width/height, i.e. when:
- minConsumptionRatioThreshold is set to 25% and fits video resolutions;
- the video resolutions are the same and minConsumptionRatioThreshold is set to 100%.

In the above cases TextureBox width/height returned from StagingTexture::mapRegion is zero for a large number of frames . This results in skipped frames/ or frames being played in the wrong video.

As a quick hack adding an offset to try to create a unique sized staging texture resolved most of the issues.

Code: Select all

    Ogre::StagingTexture* stagingTexture = me.getStagingTexture( width+videoIndex*4, height+videoIndex*4, 1, 1,
                                 textureGpu->getPixelFormat(), 100 );
Is there an alternative way of doing this without a staging texture or am I doing something wrong?


This is my texture creation:

Code: Select all

            if self.getHlms().getType()==ogre.HLMS_PBS:
                textureType = ogre.TextureTypes.Type2DArray
            else:
                textureType = ogre.TextureTypes.Type2D

            #'AlwaysKeepSystemRamCopy', 'Discard', 'SaveToSystemRam'
            textureMgr = ogre.Root.getSingletonPtr().getRenderSystem().getTextureGpuManager()
            self.videoTextureGPU = textureMgr.createTexture( self.textureName,
                                             ogre.GpuPageOutStrategy.Discard,
                                             ogre.TextureFlags.PrefersLoadingAsSRGB, 
                                             textureType,
                                             ogre.ResourceGroupManager.AUTODETECT_RESOURCE_GROUP_NAME )

            self.videoTextureGPU.setPixelFormat( ogre.PixelFormatGpu.PFG_RGBA8_UNORM ) #PFG_RGBA8_UINT )
            self.videoTextureGPU.setTextureType( textureType )
            self.videoTextureGPU.setNumMipmaps( 1 )
            self.videoTextureGPU.setResolution( self.width, self.height )
This is my code to update the texture:

Code: Select all

            self.stagingTextureDataPtr = ogre.createUint8SIMD(len(self.videoBufferData))
            ctypes.memmove(
                    ogre.castAsLongLong(self.stagingTextureDataPtr), 
                    ogre.castAsLongLong(ogre.castAsVoidPtr(ctypes.addressof(self.videoBufferData))),
                    len(self.videoBufferData) )

            rowAlignment = 4
            dataSize = ogre.PixelFormatGpuUtils.getSizeBytes( self.width, self.height, 1, 1,
                 self.videoTextureGPU.getPixelFormat(), rowAlignment )
            bytesPerRow = self.videoTextureGPU._getSysRamCopyBytesPerRow( 0 )


            self.videoTextureGPU._transitionTo(ogre.GpuResidency.Resident, 0 )
            self.videoTextureGPU._setNextResidencyStatus( ogre.GpuResidency.Resident )

            stagingTexture = textureManager.getStagingTexture( self.width, self.height, 1, 1,
                                     self.videoTextureGPU.getPixelFormat(), 100 )

            #stagingTexture = textureManager.getStagingTexture( self.width+4*self.index, self.height+4*self.index, 1, 1,
            #                         self.videoTextureGPU.getPixelFormat(), 100 )

            assert(stagingTexture.uploadWillStall()==False)

            stagingTexture.startMapRegion()
            texBox = stagingTexture.mapRegion( self.width, self.height, 1, 1,
                     self.videoTextureGPU.getPixelFormat() )

            ## stop the assert for texture box width/height 0 
            if (texBox.width>0 and texBox.height>0):
                texBox.copyFrom( ogre.castAsLongLong( self.stagingTextureDataPtr), self.width, self.height, bytesPerRow )
                stagingTexture.stopMapRegion()
                stagingTexture.upload( texBox, self.videoTextureGPU, 0, None, False )
                self.videoTextureGPU.notifyDataIsReady()

            else:
                print (stagingTexture._getSizeBytes(),dataSize,self.textureName, self.filename)
                #texBox.copyFrom( ogre.castAsLongLong( self.stagingTextureDataPtr), self.width, self.height, bytesPerRow )
                stagingTexture.stopMapRegion()  ## ??????
                self.errorCount+=1


            textureManager.removeStagingTexture( stagingTexture )
            ogre.OGRE_FREE_SIMD( self.stagingTextureDataPtr, ogre.MEMCATEGORY_RESOURCE )
            self.stagingTextureDataPtr = None
This is the above texture update in C++, to check the problem wasn't python specific:

Code: Select all

bool TextureGpuManager_uploadTo ( Ogre::TextureGpuManager& me, Ogre::GpuResidency::GpuResidency newResidency, Ogre::TextureGpu* textureGpu, Ogre::uint32 width, Ogre::uint32 height, Ogre::uint32 videoIndex, Ogre::uint32 datalen, void* data ) 
{

    bool err=false;

    Ogre::uint8 *voidDataPtr = reinterpret_cast<Ogre::uint8*>( OGRE_MALLOC_SIMD(
                                                                         sizeof(Ogre::uint8) * datalen,
                                                                         Ogre::MEMCATEGORY_RESOURCE ) );
    memcpy( voidDataPtr, reinterpret_cast<Ogre::uint8*>(data), datalen );

    //Ogre::TextureGpuManager* textureManager = Ogre::Root::getSingletonPtr()->getRenderSystem()->getTextureGpuManager();
    Ogre::uint32 rowAlignment = 4;
    Ogre::uint32 dataSize = Ogre::PixelFormatGpuUtils::getSizeBytes( width, height, 1, 1,
                 textureGpu->getPixelFormat(), rowAlignment );
    Ogre::uint32 bytesPerRow = textureGpu->_getSysRamCopyBytesPerRow( 0 );

    textureGpu->_transitionTo(Ogre::GpuResidency::Resident, 0 );
    textureGpu->_setNextResidencyStatus( Ogre::GpuResidency::Resident );

    //Ogre::LightweightMutex mMutex;
    //mMutex.lock();

    Ogre::StagingTexture* stagingTexture = me.getStagingTexture( width+videoIndex*4, height+videoIndex*4, 1, 1,
                                 textureGpu->getPixelFormat(), 100 );
    stagingTexture->startMapRegion();
    Ogre::TextureBox texBox = stagingTexture->mapRegion( width, height, 1, 1,
                     textureGpu->getPixelFormat() );
    if (texBox.width>0 && texBox.height>0) {
        texBox.copyFrom( voidDataPtr, width, height, bytesPerRow );
        stagingTexture->stopMapRegion();
        stagingTexture->upload( texBox, textureGpu, 0, 0, true );
        textureGpu->notifyDataIsReady();
    } else {
        stagingTexture->stopMapRegion();
        err = true;
    }

    me.removeStagingTexture( stagingTexture );
    //mMutex.unlock();

    OGRE_FREE_SIMD( voidDataPtr, Ogre::MEMCATEGORY_RESOURCE );
    textureGpu->notifyDataIsReady();
    return err;
}
Last edited by dermont on Thu Sep 21, 2017 3:40 pm, edited 1 time in total.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1280
Contact:

Re: v2-2 StagingTexture returns zero width/height TextureBox

Post by dark_sylinc »

Hi!

First I need to know the RenderSystem you're trying. D3D11 & GL behave differently, so this is important.

Second, let me see if I understand what you're doing:
  1. You've created a TextureGpu.
  2. You've called getStagingTexture
  3. Every frame you perform:

    Code: Select all

    stagingTexture->startMapRegion();
    box = stagingTexture->mapRegion(...);
    stagingTexture->stopMapRegion();
    stagingTexture->upload( box, textureGpu, ... );
  4. In several frames, mapRegion returns 0?
Could you modify Tutorial02_VariableFramerate to show what you're doing (i.e. so I can repro)?

Because I don't fully understand what you're doing, I can't comment on whether you're doing something wrong, we have a bug, etc. So I'll need some clarifications.
dermont
Bugbear
Posts: 812
Joined: Thu Dec 09, 2004 2:51 am
x 42

Re: v2-2 StagingTexture returns zero width/height TextureBox

Post by dermont »

dark_sylinc wrote:Hi!

First I need to know the RenderSystem you're trying. D3D11 & GL behave differently, so this is important.

Second, let me see if I understand what you're doing:
  1. You've created a TextureGpu.
  2. You've called getStagingTexture
  3. Every frame you perform:

    Code: Select all

    stagingTexture->startMapRegion();
    box = stagingTexture->mapRegion(...);
    stagingTexture->stopMapRegion();
    stagingTexture->upload( box, textureGpu, ... );
  4. In several frames, mapRegion returns 0?
Could you modify Tutorial02_VariableFramerate to show what you're doing (i.e. so I can repro)?

Because I don't fully understand what you're doing, I can't comment on whether you're doing something wrong, we have a bug, etc. So I'll need some clarifications.
Render System GL.

Yes for points 1-4, two TextureGpus with resolutions 1280x720, 720x480, frame data is received from GStreamer thread and passed to Ogre.

As you probably already guessed the TextureBox zero appears to be :
  • a) Frame 200 creates and updates a StagingTexture (minConsumptionRatioThreshold=100) for 1280x720
    Frame 200 creates and updates a StagingTexture for (minConsumptionRatioThreshold=100) 720x480
    b) Frame 201 attempts to create a StagingTexture for (minConsumptionRatioThreshold=100) 720x480
    c) In release mode TextureGpuManager::getStagingTexture:
    - uploadWillStall is always false;
    - second StagingTexture from (a) selected as 'bestCandidate' and returns zero TextureBox;
I've tried various combinations vaoManager.getFrameCount()/ vaoManager.getDynamicBufferMultiplier()/stagingTexture.getLastFrameUsed() to
move/ solve the problem without success.

If I change the TextureGpuManager::getStagingTexture the minConsumptionRatioThreshold check to force creating a new StagingTexture the
problem goes away:

Code: Select all

            if( ratio < minConsumptionRatioThreshold )
            if( ratio <=minConsumptionRatioThreshold )
I'll try and create a C++ sample and become more familiar with 2-2. Thanks for your help.

In DebugMode I thing there may be a typo for the startMapRegion performance error:

Code: Select all

    //-----------------------------------------------------------------------------------
    void StagingTexture::startMapRegion(void)
    {
        assert( !mMapRegionStarted && "startMapRegion already called!" );
        mMapRegionStarted = true;

#if OGRE_DEBUG_MODE
        if( mVaoManager->getFrameCount() - mLastFrameUsed < mVaoManager->getDynamicBufferMultiplier() &&
            ////-----> !mUserQueriedIfUploadWillStall )
            mUserQueriedIfUploadWillStall )
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1280
Contact:

Re: v2-2 StagingTexture returns zero width/height TextureBox

Post by dark_sylinc »

The "mUserQueriedIfUploadWillStall" is not a typo.
The idea is that we only warn if you didn't call willUploadStall (e.g. you never checked) and we can guess that it could stall (because you didn't wait 3 frames nor checked).

About the bug: Yeah... I'll need some code. Doesn't have to source data from disk or gstreamer. Just allocated ram with garbage and you perform the Ogre calls until it returns 0.
dermont
Bugbear
Posts: 812
Joined: Thu Dec 09, 2004 2:51 am
x 42

Re: v2-2 StagingTexture returns zero width/height TextureBox

Post by dermont »

dark_sylinc wrote:The "mUserQueriedIfUploadWillStall" is not a typo.
The idea is that we only warn if you didn't call willUploadStall (e.g. you never checked) and we can guess that it could stall (because you didn't wait 3 frames nor checked).
Ok I think I must be doing something wrong here, with the negation operator for mUserQueriedIfUploadWillStall:

Code: Select all

staging: /media/sdb11/OGREDEMOS2.2/Staging/StagingDemo.cpp:443: void PseudoVideo::update(const VideoFrame*): Assertion `!texBox.width==0' failed.
Aborted (core dumped)
Without:

Code: Select all

PERFORMANCE WARNING: Calling StagingTexture::startMapRegion too soon, it will very likely stall depending on HW and OS setup. You need to wait VaoManager::getDynamicBufferMultiplier frames after having called StagingTexture::upload before calling startMapRegion again.
staging: /media/sdb11/OGREDEMOS2.2/Staging/StagingDemo.cpp:443: void PseudoVideo::update(const VideoFrame*): Assertion `!texBox.width==0' failed.
Aborted (core dumped)
Attachments
staging.zip
(69.44 KiB) Downloaded 23 times
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1280
Contact:

Re: v2-2 StagingTexture returns zero width/height TextureBox

Post by dark_sylinc »

Thanks for the easy repro!

It was an Ogre bug.

1. Pushed the fix. It was a silly bug. Some initialization & cleanup functions were never getting called.

2. Additionally your code let me to realize something that was not evident. You don't need to call waitForData when you're uploading it yourself. It wasn't clear what it waits for. Clarified that in the comments.

Thanks for the early feedback!
Btw I'm impressed you manage to figgure it all out by just looking at the code :)

Cheers
Matias
dermont
Bugbear
Posts: 812
Joined: Thu Dec 09, 2004 2:51 am
x 42

Re: v2-2 StagingTexture returns zero width/height TextureBox

Post by dermont »

Thanks for the fix and the feedback everything running fine now.
Post Reply