[2.2]Porting my engine to 2.2

Discussion area about developing with Ogre2 branches (2.1, 2.2 and beyond)
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4438
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 904
Contact:

Re: [2.2]Porting my engine to 2.2

Post by dark_sylinc »

Yeah we clashed.
xrgo wrote:
Sun Feb 17, 2019 11:17 pm
made a PR:
https://bitbucket.org/sinbad/ogre/pull- ... hadow/diff

edit: lol https://bitbucket.org/sinbad/ogre/commi ... d5d2b781e5
well, my PR has 3 things, can you merge the other 2?
I can't manually merge your stuff because your repo fork is private. Either make it public or add me to get access, or submit a new PR without the conflicting part.

Also fixed the area light stuff. Thanks for the report!

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

dark_sylinc wrote:
Sun Feb 17, 2019 11:54 pm
I can't manually merge your stuff because your repo fork is private. Either make it public
oops, its public now

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

back to the point light shadow problem:

I tried to export the scene but it didn't export my meshes (only the one I created directly in v2, and one that is loaded from a mesh file)... so meanwhile I solve that I made another more evident case:

I have a point light in the center of this cube, and two monkeys that are suppose to cast shadows inside the cube, as you can see only the red monkey is casting a shadow...
Image
...but only because there is a plane outside the cube
Image
just to be sure... this is what I expect:
Image
I managed to do that by enclosing everything with a cube (normals pointing outside)

so the problems seems to be that "the nothing" that the shadowCamera sees is in front of everything and for that it cast shadows

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

Re: [2.2]Porting my engine to 2.2

Post by dark_sylinc »

Ok, I guess this looks like it's simple enough to be easily reproducible

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

ok, managed to export the scene (my meshes had a path in the name):
https://www.dropbox.com/s/pfgiwlj1ylifg ... e.zip?dl=0

and I tested in the Sample_SceneFormat and it works fine =( so I guess I have something configured differently

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

I haven't found the shadow problem yet but I prefer to continue with other things:
I have an integrated video capture in my engine which in old code was something like this:

Code: Select all

in init:
  mCaptureData = new unsigned char[ mVideoCaptureWidth * mVideoCaptureHeight * 4 ];  // Ogre::PixelUtil::getNumElemBytes(Ogre::PF_BYTE_BGRA) = 4;

in frameEnded:

  Ogre::PixelBox destPb( Ogre::Box( 0, 0, mVideoCaptureWidth, mVideoCaptureHeight ), Ogre::PF_BYTE_BGRA, mCaptureData );

  getOgreRenderWindow()->getTexture()->copyContentsToMemory( destPb );


  //FFMPG STUFF
  av_init_packet(&mPkt);
  mPkt.data = nullptr;    // packet data will be allocated by the encoder
  mPkt.size = 0;

  uint8_t *inData[1];
  inData[0] = static_cast<uint8_t*>( destPb.data );
  int inLinesize[1] = { 4 * mCodecContext->width };
  sws_scale(mScaleContext, inData, inLinesize, 0, mCodecContext->height,
            mFrame->data, mFrame->linesize);

  mCurrentTime += yGraphicsServices::getLastFrameTime() * 1000;

  mFrame->pts = mCurrentTime;

  /* encode the image */
  int ret;
  avcodec_send_frame(mCodecContext, mFrame );
  ret = avcodec_receive_packet(mCodecContext, &mPkt );

  if ( !ret ) {
      fwrite(mPkt.data, 1, size_t( mPkt.size ), mCaptureFile);
      av_packet_unref( &mPkt );
  }
I look at the ogre2.2changes.md and managed to make a code like this:

Code: Select all

in init: 

    mWindowTexture = getOgreRenderWindow()->getTexture();
    mAsyncTicket = mTextureManager->createAsyncTextureTicket( mWindowTexture->getWidth(),
                                                              mWindowTexture->getHeight(),
                                                              0,
                                                              mWindowTexture->getTextureType(),
                                                              mWindowTexture->getPixelFormat() );

in frameEnded:

  Ogre::TextureBox destPb;

  mAsyncTicket->download( mWindowTexture, 0, true );
  mSrcBox = mAsyncTicket->map(0);
  destPb.copyFrom( mSrcBox );
  mAsyncTicket->unmap();
  
  //FFMPG STUFF
  
its not working, but I feel like I am close, what I didn't get is this part:

Code: Select all

this->getData( mip - minMip );
what is this? is an Image2? should I Image2::convertFromTexture in everyframe?

edit: another question, how can I save each cubemap face in a different file?, mCubeTexture->writeContentsToFile does not have that

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

Re: [2.2]Porting my engine to 2.2

Post by dark_sylinc »

Hi!

I see two issues. One is a performance standpoint, the other is your actual problem. I will start with your problem.


1. You did everything right but one thing. You seem to just declare Ogre::TextureBox destPb; without valid stuff in it?
Anyway, TextureBox manipulation can be tricky, so I do suggest Image2 to encapsulate your mCaptureData pointer and take care of the details. Also please note the pointer is created with OGRE_MALLOC_SIMD, this is important.

Code: Select all

Ogre::Image2 mImage;
Ogre::TextureGpu *mWindowTexture;

//At init (MAKE SURE THE RESOLUTION IS WHAT YOU EXPECT! Check for resolution changes!!!
const uint32 rowAlignment = 4u;
const size_t totalBytes = PixelFormatGpuUtils::calculateSizeBytes( mWindowTexture->getWidth(),
                                                                   mWindowTexture->getHeight(),
                                                                   mWindowTexture->getDepth(),
                                                                   mWindowTexture->getNumSlices(),
                                                                   mWindowTexture->getPixelFormat(),
                                                                   mWindowTexture->getNumMipmaps(),
                                                                   rowAlignment );
void *data = OGRE_MALLOC_SIMD( totalBytes, MEMCATEGORY_RESOURCE );
mImage.loadDynamicImage( data, true, mWindowTexture ); //We pass mWindowTexture just to grab its metadata instead of typing mWindowTexture->getWidth, getHeight, etc

//On frameEnd:
mAsyncTicket->download( mWindowTexture, 0, true );

//getData() just fabricates a TextureBox with the right offsets given the mip level and bytes per row, bytes per image, etc
//While it's nothing fancy, there are many details to be aware, so Image2 is a great helper encapsulation utility.
Ogre::TextureBox destPb = mImage.getData( 0 ); //Get mip 0
mSrcBox = mAsyncTicket->map(0);
destPb.copyFrom( mSrcBox );
mAsyncTicket->unmap();
That should work. If it doesn't and you're grabbing the render window directly and are using OpenGL, it could be a bug. Transferring the render window in GL3+ is tricky.
If you're using MSAA, then you may need to resolve it first (see Image2::convertFromTexture).

You could use Image2::convertFromTexture which handles all cases: MSAA, non-msaa, cubemaps, 3D textures, etc.
However it won't be efficient (see next step).
It could be useful to use it to see if capturing works as intended, and to compare your code against convertFromTexture to see if you missed anything.

2. Now to the performance concerns. Your code is inefficient. You're issuing the ticket download, and immediately afterwards mapping it. That turns the async ticket into synchronous, and causes stalls.

You should have 3 mAsyncTicket, and cycle through them:

Code: Select all

On init:
idx = 0;

On frameInit:
//Read the data which we requested to download 3 fames ago
mSrcBox = mAsyncTicket[idx]->map(0);
destPb.copyFrom( mSrcBox );
mAsyncTicket[idx]->unmap();

On frameEnd:
idx = (idx + 1u) % mVaoManager->getDynamicBufferMultiplier();
//Request another download, which we'll read 3 frames later
mAsyncTicket[idx]->download( mWindowTexture, 0, false ); //No need for accurate tracking by doing it this way
In Ogre 2.1, the only way you could have asynchronous behavior is by cycling through 3 textures. Now there's no need for 3 textures, but you'll need 3 tickets.

Cheers
Matias

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

Re: [2.2]Porting my engine to 2.2

Post by dark_sylinc »

xrgo wrote:
Wed Feb 20, 2019 8:41 pm
edit: another question, how can I save each cubemap face in a different file?, mCubeTexture->writeContentsToFile does not have that
I'd suggest using a 2nd Image2 which will be a 2D view to each face:

Code: Select all

for( face in num_faces )
{
Ogre::Image2 img2dView;
img2dView.loadDynamicImage( cubemapBox.getData( 0 ).atFromOffsettedOrigin( 0, 0, face ),
                            cubemapBox.getWidth(), cubemapBox.getHeight(), cubemapBox.getDepthOrSlices(),
                            Ogre::TextureTypes::Type2D, cubemapBox.getPixelFormat(),
                            false, //Do not autodelete
                            1u ); //Just 1 mip
img2dView.save( ... );
}
If you need all mipmaps then you'll have to perform a hard copy:

Code: Select all

const uint32 rowAlignment = 4u;
const size_t totalBytes = PixelFormatGpuUtils::calculateSizeBytes( cubemapBox->getWidth(),
                                                                   cubemapBox->getHeight(),
                                                                   1u,
                                                                   1u,
                                                                   cubemapBox->getPixelFormat(),
                                                                   cubemapBox->getNumMipmaps(),
                                                                   rowAlignment );
void *data = OGRE_MALLOC_SIMD( totalBytes, MEMCATEGORY_RESOURCE );
img2d.loadDynamicImage( data,
                            cubemapBox.getWidth(), cubemapBox.getHeight(), cubemapBox.getDepthOrSlices(),
                            Ogre::TextureTypes::Type2D, cubemapBox.getPixelFormat(),
                            true, //DO autodelete
                            cubemapBox->getNumMipmaps() );

for( face in num_faces )
{
    for( all mips )
    {
        Ogre::TextureBox cubemapBox = cubemap->getData( mip );
        Ogre::TextureBox img2dBox = img2d->getData( mip );
        
        cubemapBox.sliceStart = face;
        img2dBox.copyFrom( cubemapBox );
        
    }
img2d->save( ... );
}

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

thank you!! video capture is working now!!!!

EDIT: nevermind!!!! I had out vec3 outColour; in my shader, since I used a texture with no alpha in 2.1, omit everything below

but I have the next related problem:
I have two screenshot capture modes: very high res (8K) screen capture, and 360 high res (4k) capture.

for both I created the texture in the same way:

Code: Select all

    //SCREEN CAPTURE
    mScreenShotTexture = mTextureManager->createTexture( "captureScreenShotTexture",
                                                  Ogre::GpuPageOutStrategy::Discard,
                                                  Ogre::TextureFlags::RenderToTexture,
                                                  Ogre::TextureTypes::Type2D );

    mScreenShotTexture->setResolution( highResScreenshotWidth, highResScreenshotHeight );
    mScreenShotTexture->setNumMipmaps( 1u );
    mScreenShotTexture->setPixelFormat( Ogre::PixelFormatGpu::PFG_RGBA8_UNORM_SRGB );
    mScreenShotTexture->setMsaa( 1u );
    mScreenShotTexture->_transitionTo( Ogre::GpuResidency::Resident, (uint8*)0 );
    
    
    //360 CAPTURE
    mCubemapConversionEquirectangularTexture = mTextureManager->createTexture( "cubemapConversionEquirectangularTexture",
                                                  Ogre::GpuPageOutStrategy::Discard,
                                                  Ogre::TextureFlags::RenderToTexture,
                                                  Ogre::TextureTypes::Type2D );

    mCubemapConversionEquirectangularTexture->setResolution( cubeConversionTextureWidth, cubeConversionTextureHeight );
    mCubemapConversionEquirectangularTexture->setNumMipmaps( 1u );
    mCubemapConversionEquirectangularTexture->setPixelFormat( Ogre::PixelFormatGpu::PFG_RGBA8_UNORM_SRGB );
    mCubemapConversionEquirectangularTexture->setMsaa( 1u );
    mCubemapConversionEquirectangularTexture->_transitionTo( Ogre::GpuResidency::Resident, (uint8*)0 );
and I save the capture like this:

Code: Select all

   mScreenShotTexture->writeContentsToFile( "./Captures/" + yUtils::getDateInStandardString() + ".png", 0, 0 );
   mCubemapConversionEquirectangularTexture->writeContentsToFile( "./Captures/" + yUtils::getDateInStandardString() + ".png", 0, 0 );
The mScreenShotTexture is working fine, but the mCubemapConversionEquirectangularTexture is saved as all transparent (aka empty)

the only difference is the workspace, but! its the same (actually the same pointer) that its being used for video capturing and its working.... annnnnndd if I writeContentsToFile as .jpg its working :S, but quality is awful, I need png.

I also tried the suggested code for saving the cubemap faces in different files, and the output is also empty, but in this case, its also empty in jpg
EDIT for this last sentences: I was missing the asyncticket->download() call... now cubemap face saving is also working!

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

next problem!
I create some textures by code to be used by some workspaces, gui, etc... I apply that that texture in to the diffuse of a pbs datablock and it works... but if I create another texture and then set that, it doesn't work.
If I set a texture loaded from a file and then another texture loaded from a file it works fine.

in other words: changing back and forth (for the same datablock) manually created textures is not working

I found that for the manual textures the mTexturePool is always 0x0, and for other textures is some pointer, so, in OgreHlmsTextureBaseClass.inl when I have a manual texture applied and then change to another... this if wont enter (line 339):

Code: Select all

                if( prevPool != texture->getTexturePool() )
                    textureSetDirty = true;
beacuse prevPool is 0x0 and texture->getTexturePool() is 0x0 too

is this a bug? or I am missing some step when creating the texture:

Code: Select all

            ogreTexture = mTextureManager->createTexture( texture->mTextureData.mName,
                                                          Ogre::GpuPageOutStrategy::Discard,
                                                          Ogre::TextureFlags::RenderToTexture,
                                                          Ogre::TextureTypes::Type2DArray );

            ogreTexture->setResolution( texture->mTextureData.mWidth, texture->mTextureData.mHeight );
            ogreTexture->setNumMipmaps( 1u );
            ogreTexture->setPixelFormat( Ogre::PixelFormatGpu::PFG_RGBA8_UNORM_SRGB );
            ogreTexture->setMsaa( 1u );
            ogreTexture->_transitionTo( Ogre::GpuResidency::Resident, (uint8*)0 );
thanks!

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

Re: [2.2]Porting my engine to 2.2

Post by dark_sylinc »

Yeah this sounds like a bug. I'm about to sleep so I can't see the actual code, but I'm like 90% sure it will be an Ogre but when I check the code tomorrow

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

Re: [2.2]Porting my engine to 2.2

Post by dark_sylinc »

Yeah it was a bug.
Thanks for the report!

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

thanks! its working now =), I think I just need to solve the point light shadow problem and I'll be done with the porting =D

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

regarding the point light shadow problem ( I have params["reverse_depth"] = "true"; now )... I checked in renderdoc that indeed the shadow map is 1.0 in what should be empty space, and as I scroll the timeline I see that the map actually starts with every pixel at 1.0, and I see a glClear call with Color 1,1,1,1...
so I thought that might be that the shadow texture was being clear as white, but I checked OgreCompositorShadowNode.cpp and forced every clear to black and the problem persists

still looking for more info

EDIT: its working!! i was missing some clear color to black, I got to leave now, tomorrow I will define which one is causing the problem

rujialiu
Goblin
Posts: 280
Joined: Mon May 09, 2016 8:21 am
x 33

Re: [2.2]Porting my engine to 2.2

Post by rujialiu »

xrgo wrote:
Sat Feb 23, 2019 11:22 pm
EDIT: its working!! i was missing some clear color to black, I got to leave now, tomorrow I will define which one is causing the problem
please first check EVERY shadow map is using reverse-z-aware clear colors 8-)

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

so the problem was this clear (line 1369 on OgreCompositorShadowNode.cpp):

Code: Select all

                        //Pass scene for point lights last
            shadowMapIdx = 0;
            itor = shadowParams.begin();
            while( itor != end )
            {
                const ShadowParam &shadowParam = *itor;
                if( shadowParam.atlasId == atlasId &&
                    shadowParam.supportedLightTypes & pointMask )
                {
                    //Render to cubemap, each face clear + render
                    for( uint32 i=0; i<6u; ++i )
                    {
                        CompositorTargetDef *targetDef = shadowNodeDef->addTargetPass( "tmpCubemap", i );
                        targetDef->setNumPasses( 1u );
                        targetDef->setShadowMapSupportedLightTypes( shadowParam.supportedLightTypes &
                                                                    pointMask );
                        {
                            //Scene pass
                            CompositorPassDef *passDef = targetDef->addPass( PASS_SCENE );
                            CompositorPassSceneDef *passScene =
                                    static_cast<CompositorPassSceneDef*>( passDef );
                            passScene->setAllLoadActions( LoadAction::Clear );
                            passScene->setAllClearColours( clearColour );   //<<<<<<<<<<<<<<<<<<<THIS!!!!!!!!!
                            passScene->mClearDepth = 1.0f;
                            passScene->mCameraCubemapReorient = true;
                            passScene->mShadowMapIdx = shadowMapIdx;
                            passScene->mIncludeOverlays = false;
so avobe that, where the clearColour is defined:

Code: Select all

        ColourValue clearColour;
        if( renderSystem->isReverseDepth() || useEsm )
            clearColour = ColourValue::White;
        else
            clearColour = ColourValue( 0.0f, 0.0f, 0.0f, 0.0f );
I just swaped the colors:

Code: Select all

        ColourValue clearColour;
        if( renderSystem->isReverseDepth() || useEsm )
			clearColour = ColourValue(0.0f, 0.0f, 0.0f, 0.0f);
        else
			clearColour = ColourValue::White;
and now its working fine for both reverse depth and normal. I thing that fix is correct since the "background" should be black (0.0) for reverse depth, I don't know about Esm though, maybe for that one should be white, don't know

what I don't understand is why when I exported the scene and tried it in the samples it was working :S

anyways, please check if the fix is correct, and I think I have everything working now =) have to test everything in all my apps now
edit: also tested spotlights and pssm shadows and its working fine with the fix

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

Re: [2.2]Porting my engine to 2.2

Post by dark_sylinc »

Thanks!!!

The original version was using ifdefs:

Code: Select all

        ColourValue clearColour;
#if OGRE_NO_REVERSE_DEPTH
        clearColour = ColourValue::White;
#else
        if( useEsm )
            clearColour = ColourValue::White;
        else
            clearColour = ColourValue( 0.0f, 0.0f, 0.0f, 0.0f );
#endif
When I turned it into a toggle at runtime, I made the mistake (flags named as a negatives... that's a confusing naming convention)

ESM should use white. Good thing you took a look because I wouldn't be able to repro easily.
xrgo wrote:
Mon Feb 25, 2019 4:44 am
what I don't understand is why when I exported the scene and tried it in the samples it was working :S
That's because most of our samples are using compositor scripts, which have all been modified to be reverse_depth aware.
There's only one sample using createShadowNodeWithSettings, so the bug would only manifest there.

Thanks for the research and fix!

Now it's time to wrap up the news post and remove the "WIP" from 2.2

Cheers
Matias

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

Hello! I've been testing my apps and everything is working great!! (performance so far seems the same (maybe a bit worst but not sure since I don't have single pass stereo working) )

The only thing that bothers me is that I can see white textures while they are loading. I know I can waitForData (I haven't tested it) for it to behave like ogre 2.1, but I was expecting it to work like unreal which loads lower res mips before. maybe I am wrong and its not like that? or I have to do something else? 99% of my textures are dds dx1 with generated mipmaps.

Thanks!!!

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

Re: [2.2]Porting my engine to 2.2

Post by dark_sylinc »

xrgo wrote:
Fri Mar 01, 2019 4:34 pm
Hello! I've been testing my apps and everything is working great!! (performance so far seems the same (maybe a bit worst but not sure since I don't have single pass stereo working) )
Nice!
xrgo wrote:
Fri Mar 01, 2019 4:34 pm
The only thing that bothers me is that I can see white textures while they are loading. I know I can waitForData (I haven't tested it) for it to behave like ogre 2.1
Yes. There's also TextureGpuManager::waitForStreamingCompletion() which is global for all textures currently being loaded.
xrgo wrote:
Fri Mar 01, 2019 4:34 pm
but I was expecting it to work like unreal which loads lower res mips before. maybe I am wrong and its not like that? or I have to do something else? 99% of my textures are dds dx1 with generated mipmaps.
That was the original idea but it got put in the backburner. There were several concerns:
  1. Our Image2 class loads the whole thing (all mips) in one go. We could workaround this by storing 64x64 separately (like a thumbnail cache in a large 2D Array oitd file); but it still means there's two paths (when the thumbnail is in the cache, vs when it's not)
  2. Unless we're extremely careful, there would be a lot of shader swapping: Imagine the final shader will have all of the textures in a single array texture. But while loading, we have the incomplete ones in a 64x64 array texture, and the complete ones in another. We would need at least two shader permutations. Or we could only use the 64x64 texture until all arrays are complete. What if a texture being loaded is used in multiple shaders? It gets really messy, fast.
  3. An alternative is to use the actual final 2D Array textures and take advantage of the LOD bias or MinLOD parameters to force the GPU to ignore the lower mips. This looks far more useful. However that means we need to do a lot of management and duplication of HlmsSamplerblocks (i.e. each datablock needs to ask "is at least one of our textures still being loaded?", if the answer is yes then we need to switch to the surrogate HlmsSamplerblocks); and there's also limits to the number of samplerblocks we need to watch out; AND a texture with 2048x2048 resolution, the 64x64 mip is LOD 5; while a texture with 1024x1024 the 64x64 mip is LOD 4. We could still workaround this by populating all higher mips (i.e. you could be watching at 64x64 or 32x32). This is believe it or not the path with least resistance so far; however it's still a mess; and I'd rather wait until the code written so far from 2.2 stabilizes. And white may be good enough (btw a potential alternative is to try to replace diffuse/bgdiffuse with the predominant colour of the texture; so instead of white you see brown or green, or whatever the texture is supposed to be)
  4. Another even better alternative is to create a view (SRV D3D11 MostDetailedMip, glTextureView and Metal that would point to the 64x64 slice). This is probably the best alternative yet (which admittedly I forgot until now). Now that I think of it... we could support this in the future (we already support texture views; but I'm talking about doing this behind the scenes) (*)
UE4 doesn't have this problem because they simply don't batch as aggressively as we do.

The only perfect solution would be Vulkan and D3D12 only, since bindless textures would perfectly support swapping textures without affecting the shader or samplers.

(*) Something just ticked inside my head. Supporting this feature may not be as hard as I thought (we'd still need a thumbnail cache because I don't want to refactor Image2)

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

Thank you for the explanation
dark_sylinc wrote:
Fri Mar 01, 2019 11:57 pm
Now that I think of it... we could support this in the future
Sounds great! but Its not a priority for me, I am ok with waitForData, I don't have big enough scenes for this to be a concern (yet!)
I just thought I might be doing something wrong

thanks again!

Lax
Orc
Posts: 471
Joined: Mon Aug 06, 2007 12:53 pm
Location: Saarland, Germany
x 28

Re: [2.2]Porting my engine to 2.2

Post by Lax »

Hi all,

I read the posts and 2.2 its really interesting also for me. Is there some code, where I could see the result of this topic just for orientation?
Or should I get the Ogre 2.2 source and take a look at the SamplesCommon?

Just another question: Can v1::entity still be used in 2.2?

Best Regards
Lax

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: [2.2]Porting my engine to 2.2

Post by xrgo »

Lax wrote:
Thu May 16, 2019 9:49 am
Is there some code, where I could see the result of this topic just for orientation?
I am really sorry, my engine is not open source (maybe some day, don't hold your breath), but I can share pieces of code, no problem, just ask.... the porting was very straightforward, If you noticed many of the problems I had were ogre bugs which are solved, or some stupidity by my side. I suggest you just do it!
Lax wrote:
Thu May 16, 2019 9:49 am
Just another question: Can v1::entity still be used in 2.2?
It should (can't confirm, I don't use it) the main changes in 2.2 are in the textures

cheers!

Lax
Orc
Posts: 471
Joined: Mon Aug 06, 2007 12:53 pm
Location: Saarland, Germany
x 28

Re: [2.2]Porting my engine to 2.2

Post by Lax »

Hi,

ok thanks for the information.
I think, I will just try it out!

Best Regards
Lax

zxz
Gremlin
Posts: 160
Joined: Sat Apr 16, 2016 9:25 pm
x 12

Re: [2.2]Porting my engine to 2.2

Post by zxz »

Hello!

I am also in the process of porting to 2.2, and have run into some issues regarding MSAA resolves using the GL3Plus rendersystem. I am not quite sure how the implicit resolves should work, so I might very well be doing something wrong.

A scene is rendered to a MSAA "RenderToTexture" texture using a compositor workspace. This works fine. The problem appears when this texture is then mapped to another mesh and rendered into the backbuffer. Similar artifacts to what xrgo showed in the beginning of this thread appears when the texture is used.

What seems to happen is that the texture is never resolved from the "/MsaaImplicit" texture to the non-MSAA texture. My understanding of non-explicit resolves is explained in the documentation of TextureFlags::MsaaExplicitResolve:
Without explicit resolves, Ogre will automatically resolve the MSAA
surface into the texture whenever it detects you will be sampling
from this texture.
That seemed to happen in 2.1, but doesn't work for me using 2.2.

I have read about store actions and StoreAction::MultisampleResolve, which have been mentioned in this thread. However, having to set this manually on the last pass to touch the texture sort of goes against the purpose of implicit resolves, as I quite explicitly have to point out where the resolve should take place. This makes it hard to make general compositor workspaces that work both for MSAA and non-MSAA targets, without having to know up front which texture will be used in the compositor channel of the workspace.

There also seem to be some complications with using StoreAction::MultisampleResolve and/or StoreAction::StoreAndMultisampleResolve when the target is a render window. I would expect that the compositor setup shouldn't have to know which sort of output channel will be used, and how the output texture will be used after rendering is done.

Still, I tried using StoreAction::MultisampleResolve on the last pass touching the texture, in order to get things working. This led to a few issues:

1. If the output channel is a render window, the following exception is thrown:
https://github.com/OGRECave/ogre-next/b ... s.cpp#L369
This can be solved by only setting the MultisampleResolve-action on non-renderwindows, but I would like the compositor setup to be ignorant of this difference. This can be solved by adding another condition to the if-statement two steps above the exception, checking whether or not the texture is a renderwindow.

2. Now, if the actual target is NOT a multisample texture, the following exception is hit: https://github.com/OGRECave/ogre-next/b ... r.cpp#L191
I solved this for now by removing that check. This can also be worked around by not using a resolving store action, but again, I would prefer if the compositor didn't know this fact.

3. With the fixes above, the store action will resolve the texture when it is a MSAA texture and not a render window. However, after the resolve, the texture is immediately invalidated. The following line seems to invalidate the resolved non-MSAA target, while I think it is supposed to invalidate the MSAA texture itself: https://github.com/OGRECave/ogre-next/b ... r.cpp#L706

This can be fixed by changing GL_FRAMEBUFFER to GL_READ_FRAMEBUFFER on the same line (or worked around by using StoreAndMultisampleResolve as store action, which skips the invalidation step).

Is there some easier way that I have missed? I can't quite see where the texture is supposed to be resolved implicitly "whenever it [Ogre] detects you will be sampling from this texture".

Thanks!

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

Re: [2.2]Porting my engine to 2.2

Post by dark_sylinc »

Hi!

The main problem is that you're trying either StoreAction::MultisampleResolve (only works if the texture is MSAA) or StoreAction::Store (will never resolve).

The behavior you want, and the default one, is to use StoreAction::StoreOrResolve: This will use Store if the texture is not MSAA (or if the texture is explicit MSAA and no resolve target was specified) and it automatically switches to StoreAction::MultisampleResolve instead if the texture is implicit-resolve MSAA.
This is the behavior most people will want and will "just work" for most use cases.

Now, onto your specific problems and clarifying what's happening:
1. If the output channel is a render window, the following exception is thrown:
https://github.com/OGRECave/ogre-next/b ... s.cpp#L369
This can be solved by only setting the MultisampleResolve-action on non-renderwindows, but I would like the compositor setup to be ignorant of this difference. This can be solved by adding another condition to the if-statement two steps above the exception, checking whether or not the texture is a renderwindow.
That's what StoreOrResolve is for. It just lets you forget about whether the target is MSAA or not.
2. Now, if the actual target is NOT a multisample texture, the following exception is hit: https://github.com/OGRECave/ogre-next/b ... r.cpp#L191
I solved this for now by removing that check. This can also be worked around by not using a resolving store action, but again, I would prefer if the compositor didn't know this fact.
Same here, StoreOrResolve is to avoid these cases.
However, having to set this manually on the last pass to touch the texture sort of goes against the purpose of implicit resolves, as I quite explicitly have to point out where the resolve should take place.
With StoreOrResolve you shouldn't have to worry about this. However having that said:
  1. Ogre tries a lot to merge multiple following passes in order to only resolve once. However this isn't always possible and redundant resolving may happen (i.e. draw -> resolve, draw some more -> resolve) which you can debug via RenderDoc. Forcing all passes to "Store" and the last pass set to "StoreOrResolve" is one way to be absolutely sure resolving happens only once, at the end.
    This is from a performance optimization perspective. Visually you wouldn't notice a thing other than higher framerate (assuming you're not actually using the texture halfway through rendering before the final resolve).
  2. In some cases you'll have to use explicit resolves; such as if you want to use MSAA with cubemaps (or Texture2DArray). Supporting implicit MSAA resolves with cubemaps could be possible, but for now it's not implemented as it's a pandora's box of bugs to open: since the hidden MSAA surface is of type 2D while the cubemap is of type Cubemap (type mismatch). There's also the problem that if someone wants to use multi-viewport rendering with MSAA, we can't have just one MSAA surface for all 6 faces. The script Samples/Media/2.0/scripts/Compositors/Tutorial_DynamicCubemap.compositor shows how to do MSAA cubemap rendering.
    Likewise some algorithms prefer explicit MSAA (e.g. HDR with proper resolving, SSAO, SSR)
  3. If you need access to the MSAA contents, then you'll have to use explicit resolves. That's where Store, Resolve, and StoreAndResolve come in handy:
    • If you want to render additional stuff in subsequent passes, then use: "Store" followed by either "Resolve" or "StoreOrResolve" at the end. Using "Resolve" is one way to ensure you didn't accidentally forget to set the Resolve texture (explicit resolves means everything is set manually) as the exception will be raised; while StoreOrResolve will silently execute the compositor and you're left wondering why your resolve texture is either blank, garbage, or contains old results.
    • If you don't want to render additional stuff, e.g. you want to access the MSAA contents for a fancy algorithm AND at the same time use the resolved contents as a texture somewhere else; use StoreAndResolve. Hence you'll have available the contents of both the MSAA surface and the resolved content at your disposal at the same time. On iOS with chips A11 or newer, StoreAndResolve also follows an optimized path.
However, after the resolve, the texture is immediately invalidated. The following line seems to invalidate the resolved non-MSAA target, while I think it is supposed to invalidate the MSAA texture itself:
Mmmm it appears you're right. When resolving, the MSAA contents we want to invalidate will be bound to GL_READ_FRAMEBUFFER instead of GL_DRAW_FRAMEBUFFER; and thus the wrong FBO will be invalidated.
Good catch! Fix pushed.

Post Reply