Page 1 of 1

[2.1] creating items that aren't visible immediately

Posted: Tue Mar 20, 2018 4:28 am
by ikyle620
How do I tell an item to "fully load" even when it hasn't appeared on the screen yet?

I've taken the multithreaded tutorial and added keypresses to add and subtract items from a logic-side list (all Cubes). When I start the application with zero cubes, and keypress to add the first cube, there is a noticeable freeze in the application- presumably loading that first item 's mesh into existence. After loading that first cube, I can then add as many cubes as I want instantaneously. In addition to that, I can subtract down to zero and re-add the first cube and it is instantaneous. How do I make that first cube appear instantaneously?

My initial reaction is that the application has, prior to adding the first cube, never encountered a cube mesh, and thus needs to load a cube mesh into existence. I've tried was adding a SceneManager->createItem(...) call in the Graphics' side createScene01(), but that alone doesn't change any behavior. I then attached it to a scene node, which obviously draws it to the scene at that location (which I don't want). I've also attempted to createResourceGroup("TEST"), createItem("Cube_d.mesh", TEST"...), and prepareResourceGroup("TEST") as a shot in the dark, but that didn't work as well (I obviously have no idea what resource groups are, but I'll figure them out later).

I presume that there is some behind the scenes black magic that is not allowing the item to be created until it is actually in the scene- how would I demand ogre to load/prepare that item?

Re: [2.1] creating items that aren't visible immediately

Posted: Tue Mar 20, 2018 5:04 am
by dark_sylinc
Hi!

There are two things involved:
  • Mesh loading. This happens once when you create your first Item (i.e. via SceneManager::createItem) or when you explicitly call Mesh::load.
  • Shader generation. This happens when the item appears on screen. The generated shader may depend on mesh and/or material involved, but multiple meshes / materials may or may not share shaders. If the shader hasn't been compiled yet, it will cause a small delay or noticeable stall.
I suspect what you're seeing is mostly the second problem (shader generation and compilation). This is a known issue. We strongly suggest to use the Microcode cache and/or have a warm up scene. See the Ogre 2.1 FAQ regarding slow shader compile times and the microcode cache.

Cheers

Re: [2.1] creating items that aren't visible immediately

Posted: Wed Mar 21, 2018 6:38 am
by ikyle620
I hadn't considered it being the shader creations, even though I've noticed that happening live when playing with the tutorials. Thanks!

Re: [2.1] creating items that aren't visible immediately

Posted: Thu Apr 12, 2018 6:16 am
by ikyle620
I'm finally getting around to attempting this microcache stuff, but I don't appear to get any results. I've chosen to continue this thread as it directly relates to the answer given previously- http://wiki.ogre3d.org/Ogre+2.1+FAQ#Sta ... irect3D11_

I've placed my

Code: Select all

GpuProgramManager::getSingleton().setSaveMicrocodesToCache( true ); //Make sure it's enabled.
DataStreamPtr shaderCacheFile = root->openFileStream( "D:/MyCache.cache" );
GpuProgramManager::getSingleton().loadMicrocodeCache( shaderCacheFile );
right before BaseSystem::initialize() in my GraphicsSystem::initialize(), and placed

Code: Select all

DataStreamPtr shaderCacheFile = root->createFileStream( "D:/MyCache.cache", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true );
GpuProgramManager::getSingleton().saveMicrocodeCache( shaderCacheFile );
at the very beginning of deinitialize().

When I run my F3D/Multithreaded tutorial mix for the first time, I get the expected performance hiccups from shader generation. I get one compiling warning immediately, an additional compile and hiccup the first time I camera-look left (at some never-before-rendered objects), and a final compile and hiccup when I move the camera 180 degrees (for one last shader compile). The warnings look like this:

Code: Select all

Warnings while compiling D3D11 high-level shader 536871424PixelShader_ps:
C:\TestCode\TestOgre\x64\Debug\536871424PixelShader_ps.hlsl(839,12): warning X3078: 'i': loop control variable conflicts with a previous declaration in the outer scope; most recent declaration will be used
I then close the application.

On my second run through, i get 2 second hiccups in all the same spots (immediate, look left, 180 spin), but I do not get the shader compiler warnings. I presume this to mean that the microcode cache worked to some degree- I guess, as a side question, are there still supposed to be large (1+ second) pauses? Maybe the fact that the shader throws warnings at compile ruins everything?

Continuing with my observations though- if I close the application and run again, the cycle restarts and it has to recompile and I get the warnings again. I did some minor debugging and found that every other run, the cache believes there isn't anything there.

To make this easily reproducible, I added the microcodeCache changes to the places I mention earlier in both the provided Sample_Forward3D and Sample_Multithreaded tutorials, and with every execution of the application, MyCache.cache would alternate in size, from X bytes to 0 bytes, repeating. I'm assuming that is a bug? Or maybe saveMicrocodeCache() call needs to be made earlier in the process (which I've tried in a few spots but there was no difference)? Maybe I need a newer pull of Ogre 2.1 (I'm like January?)

Re: [2.1] creating items that aren't visible immediately

Posted: Sun Apr 15, 2018 10:03 pm
by ikyle620
The solution to the .cache file alternating between 0 and X bytes can be found here:
viewtopic.php?f=25&t=83624&p=518562&hil ... ty#p518562
Most specifically:
You can check if the shader cache is dirty by calling isCacheDirty before saving. If it's not dirty, do not save the file.


However, I am still experiencing hiccups when I don't think I should be. I downloaded the latest push of 2.1 and am able to replicate the hiccups I'm seeing in the provided Forward3D sample-
1) Load the sample- after clicking "OK" in the ogre engine rendering setup, try not to use the mouse anymore.
2) Move to the left with (Shift+A) for four seconds.
You'll see a huge hiccup, regardless of whether or not you use the microcache. At this point, I don't know where this hiccup is coming from, other than it happens on both clustered and F3D (so it isn't those). I'll be looking into other tutorials to see if I can get a similar stall.

Re: [2.1] creating items that aren't visible immediately

Posted: Sun Apr 15, 2018 11:24 pm
by dark_sylinc
In Forward3D by doing that, eventually you leave the reach of the spotlights (which are shadow-casting), thus a new (faster) shader is compiled that doesn't contain the spotlight.

There can be 3 shader permutations (both spotlights, one spotlight, no spotlight on camera), so all of them have to be in the shader cache for the experience to be fully hiccup free.

Re: [2.1] creating items that aren't visible immediately

Posted: Sun Apr 15, 2018 11:58 pm
by ikyle620
Whenever I do the steps listed above though, the hiccup remains (presumably I'd be hitting the same required shader and grabbing it from the cache after the first run)- in addition to that, the .cache file never changes in size, and the isCacheDirty() function returns false after hitting the hiccup. It also happens in ForwardClustered if that is relevant.

Re: [2.1] creating items that aren't visible immediately

Posted: Mon Apr 16, 2018 12:50 am
by ikyle620
One last update for the night-

I've been running both OpenGL and DX11 (both have the hiccup), and I've noticed that after continuously starting and stopping the app, if I run with F3D and move the camera left, in DirectX11 I don't hit the GpuProgramManager::addMicrocodeToCache() function, whereas I hit it everytime with OpenGL (via GLSLMonolithicProgram::compileAndLink()). In addition, when I hit it in OpenGL, the hash is found in the table, and nothing is added and dirty is not set. I don't know if I should expect D3D11HLSLProgram::compileMicrocode() to be called at the hiccup or not. To be more clear, addMicrocodeToCache() gets hit a bunch of times at startup (in both DX and OpenGL), which looks like it is to be expected.

Re: [2.1] creating items that aren't visible immediately

Posted: Tue Apr 17, 2018 2:26 am
by ikyle620
I found an october post that appears to be relevant to my problem:
viewtopic.php?f=25&t=93672&p=539464&hil ... de#p539464

Most specifically, I was looking at the following:
2. It looks like the wrong parameter is being passed to getMicrocodeFromCache. In here OgreGLSLProgram.cpp-235 and here OgreGLSLMonolithicProgram.cpp-121 getCombinedName() is used whereas I think it should be getCombinedSource() since that's what's used as key when adding a new entry in OgreGLSLMonolithicProgram.cpp-247.

I noticed that the line in question hasn't changed, but I assume the fix discussed in this post is actually in (the entire function probably changed, as evidenced by the fact that line 247 doesn't have a getCombinedSource() in it). This did lead me to GLSLMonolithicProgram::activate(void) though, and after running the program multiple times (in opengl), I can confirm that nothing ever hits the "getMicrocodeFromCache()" on line 123- everything goes through compileAndLink() on 127.


I then looked into what was being passed into computeHashWithRenderSystemName(source) at lines 262 and 277 of OgreGpuProgramManager.cpp, and they appear to be different formats-
For example, the parameters that get passed into GpuProgramManager::isMicrocodeAvailableInCache(...) look like this:

Code: Select all

"Vertex Shader: 536903680VertexShader_vs\n"
whereas the parameter for the GpuProgramManager::addMicrocodeToCache(...) looks like this:

Code: Select all

"\n\n#version 330 core\n\n\n    #extension GL_ARB_shading_language_420pack: require\n    \n\n    \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\r\n\r\n\r\nout gl_PerVertex\r\n{\r\n\tvec4 gl_Position;\r\n\n};\r\n\r\nlayout(std140) uniform;\r\n\r\n\nmat4...

Is this incorrect? I'm digging deep because, if I look at the behavior of the .cache file, it appears to be storing data. It grows when I encounter a shader I haven't seen before, but stays the same when i re-encounter a shader i've seen before (those re-encounters still involve a hiccup though). I assume this hash lookup is a problem, only because on startup it appears as though the cache hashes are not matching, one has a name, the other has the first portions of the actual shader source.

EDIT::: *****
Line 247 Actually still has getCombinedSource() as its parameter to addMicrocodeToCache- I had the wrong file open. It is line 247 of OgreGLSLMonolithicProgram.cpp, as the quote says, and not OgreGLSLProgram. My mistake. Was this fixed?

Re: [2.1] creating items that aren't visible immediately

Posted: Tue Apr 17, 2018 2:40 am
by dark_sylinc
Nice catch there!
isMicrocodeAvailableInCache(getCombinedName()) looks very wrong.

What happens when you change it for isMicrocodeAvailableInCache( getCombinedSource() ) ?

We need to hash the source and lookup by hash of the source, not of the name of the shader (because the source code may change but the name still remain; the name is useless).

Edit: Nevermind, fixed it. Thanks for the investigation!

Re: [2.1] creating items that aren't visible immediately

Posted: Tue Apr 17, 2018 2:55 am
by ikyle620
I'll pull the update shortly, but do note I see this problem (perhaps different versions of it) on both DirectX and OpenGL.

I'll let you know if I find anything else.

Re: [2.1] creating items that aren't visible immediately

Posted: Tue Apr 17, 2018 3:00 am
by ikyle620
Bad news, changing it to getCombinedSource() blows me up (on the second run through).

Debug Assertion Failed!

Program: C:\\Windows\System32\MSVCP120D.dll
File: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtree
Line: 237

Expression: map/set iterator not dereferencable

For information on how....

Seeing if I can pinpoint where exactly.

GLSLProgram::getMicrocodeFromCache(void), line 235. Probably need another getCombinedSource() instead of getCombinedName()?

Yea that looks like it.

Still though, I'm getting the hiccup when shift-lefting, even after all of this. Ill look into it more.

Re: [2.1] creating items that aren't visible immediately

Posted: Tue Apr 17, 2018 3:10 am
by dark_sylinc
Fixed. Thanks!

What sneaky bas###d!
ikyle620 wrote: Tue Apr 17, 2018 3:00 am Still though, I'm getting the hiccup when shift-lefting, even after all of this. Ill look into it more.
That's weird. If that was the last of the bugs and the file is getting saved correctly, the problem should be gone (unless the driver is reporting they support shader caches and they just stored a source version they recompile).

Re: [2.1] creating items that aren't visible immediately

Posted: Tue Apr 17, 2018 3:15 am
by ikyle620
I'm hitting the compileAndLink(); located @ 259 in OgreGLSLProgram.cpp, meaning glGetProgramiv() is pointing out that mGLProgramHandle isn't linked successfully. It would imply the problem is right here.

I'll get to it. But I feel done for the day.

Thanks!

Re: [2.1] creating items that aren't visible immediately

Posted: Tue Apr 17, 2018 3:52 am
by dark_sylinc
Out of curiosity I decided to try it. I'm cheating because I'm on Linux and I've got Mesa source code, so I can see better what goes wrong.

The first thing that popped out is that:

Code: Select all

OGRE_CHECK_GL_ERROR(glProgramBinary(mGLProgramHandle,
                                    binaryFormat,
                                    cacheMicrocode->getPtr(),
                                    binaryLength));
Should be:

Code: Select all

OGRE_CHECK_GL_ERROR(glProgramBinary(mGLProgramHandle,
                                    binaryFormat,
                                    cacheMicrocode->getCurrentPtr(),
                                    binaryLength));
However this isn't enough. The header of the microcode inside the driver now checks out, but the sha1 checksum is failing (so we got the microcode partially correct, but not entirely); meaning that we're either:
  1. Retrieving the microcode out of the driver incorrectly on the first run
  2. Incorrectly saving the code to disk
  3. Incorrectly loading it from disk (most likely) or providing wrong blob size in bytes
  4. All of the above
Edit: According to the header in the blob we provide to Mesa, the blob should be 35953 bytes, but according to us, it is 35985. This is correct. Mesa just stores 32 bytes for the header and 35953 bytes for the binary part, making it 35985. The size is not the problem.
Edit 2: It appears my microcode had gone corrupted (probably saved incorrectly). A fresh build of the cache was ok. However this may indicate the cache is prone to corruption when we write to it, for some reason.
I've pushed some fixes.

Re: [2.1] creating items that aren't visible immediately

Posted: Wed Apr 18, 2018 5:17 am
by ikyle620
I still am experiencing the hiccup, but I can't find anything wrong in the areas discussed previously. I no longer hit compileAndLink() in GLSLProgram::getMicrocodeFromCache()- things appear to work as expected there? So I tried a completely different approach.

I've tried to narrow down the first abnormal thing that happens when the freeze begins, and the line that I've reached is line 2645 of OgreHlms.cpp in Hlms::getMaterial(...)

Code: Select all

            lastReturnedValue = this->getShaderCache( finalHash );
            
            if( !lastReturnedValue )
            {
                lastReturnedValue = createShaderCacheEntry( hash[0], passCache, finalHash,
                                                            queuedRenderable );
            }
getShaderCache( finalHash ) returns 0, thus kicking off createShaderCacheEntry(...).

Do I expect getShaderCache( finalHash ) to return a non zero value when utilizing the microcache?

A point to note would be that everytime I shift left and hit this hiccup (and this breakpoint), the createShaderCacheEntry(...) call returns an HlmsCache* with the same hash value. Another point to note would be that, on startup but after loadMicrocodeCache(shaderCacheFile), mShaderCache has no items in it, so getShaderCache( finalHash ) on line 2641 won't return any values at that time (and I hit the breakpoint and call createShaderCacheEntry(...) multiple times at startup).

Is loadMicrocodeCache(shaderCacheFile) supposed to fill mShaderCache?

Re: [2.1] creating items that aren't visible immediately

Posted: Wed Apr 18, 2018 7:01 pm
by dark_sylinc
I forgot to mention; and yes you're correct... the microcode does not save the cache from the Hlms, thus on first time it still tries to generate a shader. The Hlms'es could try to saved their own caches separately without much effort, but it's not implemented.

The thing here though, the Hlms is usually very fast; but there can still be a small hitch while in debug mode (particularly slow are the @foreach, specially if they get nested and repeat a lot), but in Release mode it's pretty much too fast to notice; but if the hit is noticeable in Release let me know.

Re: [2.1] creating items that aren't visible immediately

Posted: Wed Apr 18, 2018 9:43 pm
by ikyle620
I haven't actually tried release mode- I'll let you know how that goes when I get the chance to test it.

Re: [2.1] creating items that aren't visible immediately

Posted: Thu Apr 19, 2018 3:05 am
by ikyle620
Wow- on release, the hiccup is orders of magnitude faster- it is only about~70ms (while average frame time is 2ms-4ms). I would imagine that isn't particularly wanted, but I'm satisfied for now- are there plans to reduce that?

Re: [2.1] creating items that aren't visible immediately

Posted: Thu Apr 19, 2018 4:40 am
by dark_sylinc
That is considerable time. It appears I underestimated the ability to save the Hlms' cache, it may be more important than I thought. Maybe the Hlms implementations kept getting slower to the point we're now.

Re: [2.1] creating items that aren't visible immediately

Posted: Sat Apr 21, 2018 6:10 am
by zxz
These recent fixes made to the shader cache prompted me to check out the shader cache again, since I hadn't had much luck with it before.

After loading the shader cache, upon rendering the first quad pass. I got a segfault at RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp:2497

Code: Select all

              GLSLMonolithicProgram* monolithicProgram = GLSLMonolithicProgramManager::getSingleton().getActiveMonolithicProgram();
              if (monolithicProgram)
              {
                  updateVAO = !monolithicProgram->getVertexArrayObject()->isInitialised(); // <---- HERE
  
                  monolithicProgram->getVertexArrayObject()->bind();
              }
              else
              {
                  Ogre::LogManager::getSingleton().logMessage(
                      "ERROR: Failed to create monolithic program.", LML_CRITICAL);
              }
It turns out that mVertexArrayObject of the monolithic program is nullptr after a program has been loaded from the cache.

I am not sure why the shader programs keep a vertex array object in thje first place, so I won't attempt a proper fix. However, the workaround below allowed me to bypass the segmentation fault and see the shader cache working for the first time :!: I haven't benchmarked things, but loading time feels noticably quicker.

Code: Select all

diff -r 37134d977192 RenderSystems/GL3Plus/src/GLSL/OgreGLSLProgram.cpp
--- a/RenderSystems/GL3Plus/src/GLSL/OgreGLSLProgram.cpp        Sat Apr 21 02:11:48 2018 +0200
+++ b/RenderSystems/GL3Plus/src/GLSL/OgreGLSLProgram.cpp        Sat Apr 21 07:01:05 2018 +0200
@@ -269,6 +269,7 @@
         else
         {
             mLinked = true;
+            mVertexArrayObject = new GL3PlusOldVertexArrayObject();
         }
     }

Re: [2.1] creating items that aren't visible immediately

Posted: Sat Apr 21, 2018 12:46 pm
by paroj
I am not sure why the shader programs keep a vertex array object in thje first place, so I won't attempt a proper fix.
you can sefely remove all references - it was conceptually wrong.

see: https://github.com/OGRECave/ogre/commit ... 7281d711bf

Re: [2.1] creating items that aren't visible immediately

Posted: Sat Apr 21, 2018 5:34 pm
by zxz
paroj wrote: Sat Apr 21, 2018 12:46 pm
I am not sure why the shader programs keep a vertex array object in thje first place, so I won't attempt a proper fix.
you can sefely remove all references - it was conceptually wrong.

see: https://github.com/OGRECave/ogre/commit ... 7281d711bf
Thanks for the heads up!

This raises a concern though. I see that you're doing a lot of useful work on the 1.x branch that isn't being carried forward. There don't appear to be many merges taking place between 1.1x -> 2.1. What is the plan with these seemingly diverging branches? It would be nice if they could benefit from each other and work toward a common goal.

Cheers

Re: [2.1] creating items that aren't visible immediately

Posted: Sat Apr 21, 2018 9:48 pm
by paroj
the last attempt to merge 1.x into 2.x was about a year ago and was aborted due too many conflicts. Today the branches diverged far beyond a point where merges can be performed semi-automatically.
I agree that this situation is subpar, but unfortunately we have neither a solution nor a plan to implement it at the moment.

Currently I resort to cherry-picking applicable changes from 2.x to 1.x manually.