[2.3] Getting clarity on things that might break instancing

Anything and everything that's related to OGRE or the wider graphics field that doesn't fit into the other forums.
Post Reply
psysu
Kobold
Posts: 28
Joined: Tue Jun 01, 2021 7:47 am
x 1

[2.3] Getting clarity on things that might break instancing

Post by psysu »

Hi, im upgrading our current project which is running on Ogre 1.x to Ogre-next. i have implemented a new Hlms which inherits features from HlmsPbs, to add additional properties on top of HlmsPbs for our use cases.

while im working on this, im not clear about how the auto-instancing works in Ogre-Next. if someone can provide clarity on how auto-instancing in Ogre-Next works and stuffs that can break the instancing, it would be really helpful.

thanks

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

Re: [2.3] Getting clarity on things that might break instancing

Post by dark_sylinc »

From a 10.000km overall view, auto instancing reduces to this:

Code: Select all

// We have this:
for( int i < numObjects )
{
	drawCall( renderable[i] );
}

// We want to turn it into this:
drawCalls( renderable, numObjects );

The way we achieve this is conceptually very simple:

Code: Select all

lastDrawnObjStart = 0;
numObjsToDraw = 0;
for( int i < numObjects )
{
    if( needsMoreCommands[i] )
    {
        // Draw everything accumulated so far
        drawCalls( &renderable[lastDrawnObjStart], numObjsToDraw );
        lastDrawnObjStart = numObjsToDraw;
        numObjsToDraw = 0;

    // Set new shader
    setShader( renderable[i] );

    // Keep accumulating
    ++numObjsToDraw;
}
else
{
    // Keep accumulating
    ++numObjsToDraw;
}
}

// Draw everything accumulated so far
drawCalls( &renderable[lastDrawnObjStart], numObjsToDraw );

That is, we start accumulating objects to render until we find a something that breaks the instancing, submit what we have so far, issue that breaking call, and then start accumulating again.

Now, what you are you asking is "what causes needsMoreCommands[i] to be true".

Well... anything that isn't a draw call:

  • Any change in HlmsBlendblock

  • Any change in HlmsMacroblock

  • Any change in HlmsSamplerblock

  • Needing a different shader

  • Any change in vertex format

  • Binding new const / texture buffers

  • Any change in texture pools

Because of a technique called AZDO and MultiDraw, we don't usually need to break auto instancing for different meshes or vertex buffers.

As for textures, we try to aggressively use AutomaticBatching, where we put lots of textures together into one pool (i.e. we externally pretend a single TextureGpu is alone a Type2D, when internally it actually is a slice of a Type2DArray) so that we don't have to issue setTexture() calls frequently, thus increasing the chances of auto instancing.
If 2 Items use different textures but they are living in the same pool, auto instancing won't be broken because internally the same texture is still bound.

In short, every time we need to call:

Code: Select all

commandBuffer->addCommand<T>()

the instancing will be broken up.

If you are writing your own HlmsPbs modification, you need to be care of not calling commandBuffer->addCommand<T>() with every fillBuffersFor call.

We use key sorting in OgreRenderQueue.cpp (as long as the sort mode for that particular queue isn't DisableSort) to group everything by state as much as possible (e.g. transparents are the hardest because sorting back to front takes priority) and thus maximize the chance of auto instancing (e.g. all Items using the same shader should be grouped together).

psysu
Kobold
Posts: 28
Joined: Tue Jun 01, 2021 7:47 am
x 1

Re: [2.3] Getting clarity on things that might break instancing

Post by psysu »

Thanks for answering this in detail.

Also, i have another question, why stuffs like Ogre::RenderQueue::RenderableListener not present in Ogre-Next, im guessing here.. is it because of this new approach. is there a way to get callbacks for Ogre::Renderable that is about to be rendered in Ogre-Next ?

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

Re: [2.3] Getting clarity on things that might break instancing

Post by dark_sylinc »

Per-renderable listeners would sit in the most performance sensitive area (e.g. if we have 100k objects too render, that's 100k listener calls), so we discourage this type of approach on purpose.

If possible try to refactor things at per pass level (e.g. CompositorWorkspaceListener::passPreExecute or passEarlyPreExecute; or HlmsPbs::preparePassHash or HlmsListener::preparePassHash).

For example you can place all your specific Renderables into a specific RenderQueue and create a render_scene pass just for that RenderQueue ID. Therefore you can be sure pass-level calls like passPreExecute will only deal with Renderables that you care about.

In a few cases it's possible to refactor things per renderable at material-assignation time (i.e. HlmsListener::shaderCacheEntryCreated or propertiesMergedPreGenerationStep).

But if you really need per-renderable calls, every frame; then the only place to do this reliably is to overload Hlms::fillBuffersFor.

psysu
Kobold
Posts: 28
Joined: Tue Jun 01, 2021 7:47 am
x 1

Re: [2.3] Getting clarity on things that might break instancing

Post by psysu »

Thanks, i will look into these things you mentioned

Post Reply