Get Batch and Triangle count

Discussion area about developing with Ogre2 branches (2.1, 2.2 and beyond)
Post Reply
xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Get Batch and Triangle count

Post by xrgo »

Hello! I am not sure if this is something related with Ogre 2.0+.
I am having problems getting current batch and triangle count
I remember while ago (dont remember what ogre version) using this code worked for me:
renderWindow->getStatistics().triangleCount;
renderWindow->getStatistics().batchCount;
or this one
renderWindow->getTriangleCount();
renderWindow->getBatchCount();

but now its always 0

whats the correct way to get this values now??

Thanks in advance!

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

Re: Get Batch and Triangle count

Post by dark_sylinc »

This feature just hasn't been implemented yet :(

We probably should gather the statistics in RenderQueue::renderXX, using the recently deleted VertexArrayObject::mFaceCount variable (should be renamed to mTriangleCount), see VertexArrayObject::VertexArrayObject's commented code.

However "batch" count is now outdated, since it doesn't make sense now.
A more useful statistic would be to gather the number of draws (one Renderable = one draw), and the number of API draw calls (RenderSystem-specific).

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 241
Joined: Wed Apr 23, 2014 3:49 pm
x 45

Re: Get Batch and Triangle count

Post by TaaTT4 »

Has been any progress on this topic? I'd like to see triangles and draw calls count in real time. I'd prefer to collect these data directly from OGRE, but I'm also open to a 3rd party tool. Since I've never used it before, does Remotery provide these info?
Senior game programmer at Vae Victis
Working on Racecraft

al2950
OGRE Expert User
OGRE Expert User
Posts: 1221
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 154

Re: Get Batch and Triangle count

Post by al2950 »

I find these numbers a little tricky in a modern engine architecture. Especially when a customer places a requirement on something like triangle limit, that would have made sense in 2005!

Having said that some things can be useful, and I use render doc which gives a really good breakdown of not only the draw calls, but resource binding calls, shader sets, etc, as well as mem usage. Just need to capture a frame and go to Window->Statistics Viewer.

The only thing it does not do is the number of ogre renderables (for obvious reasons!), due to ogre batching, but to be honest thats not that useful.

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 241
Joined: Wed Apr 23, 2014 3:49 pm
x 45

Re: Get Batch and Triangle count

Post by TaaTT4 »

al2950 wrote:
Mon Oct 28, 2019 5:08 pm
I find these numbers a little tricky in a modern engine architecture.
I could disagree this... Both Unity and Unreal Engine show that old-generation stats :D Anyway, due the procedural nature of my game, showing those numbers would be helpful (eg for artists).
al2950 wrote:
Mon Oct 28, 2019 5:08 pm
I use render doc which gives a really good breakdown of not only the draw calls, but resource binding calls, shader sets, etc, as well as mem usage. Just need to capture a frame and go to Window->Statistics Viewer.
I use Renderdoc too, but the "problem" is that it doesn't work in realtime (you have to dump a frame and then analyze it). Instead I'd like to have a preview of what's happening under the hood (eg draw calls count) so I can track where the issues reside and then inspect them in deep with Renderdoc.
Senior game programmer at Vae Victis
Working on Racecraft

al2950
OGRE Expert User
OGRE Expert User
Posts: 1221
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 154

Re: Get Batch and Triangle count

Post by al2950 »

Fair enough!

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

Re: Get Batch and Triangle count

Post by dark_sylinc »

To anyone interested in contributing, RenderQueue::renderGL3 & co. perform main rendering.

The main values to consider are in vao->mPrimCount and instanceCount.

Save the value of vao->mPrimCount and instanceCount. When a new mesh is encountered, add to the stats: accumulatedStats += primCount * instanceCount;

Just don't read from drawStripPtr/drawIndexedPtr/drawCountPtr because that pointer may be write-combined.

rujialiu
Goblin
Posts: 294
Joined: Mon May 09, 2016 8:21 am
x 35

Re: Get Batch and Triangle count

Post by rujialiu »

dark_sylinc wrote:
Wed Oct 30, 2019 3:26 pm
To anyone interested in contributing, RenderQueue::renderGL3 & co. perform main rendering.

The main values to consider are in vao->mPrimCount and instanceCount.

Save the value of vao->mPrimCount and instanceCount. When a new mesh is encountered, add to the stats: accumulatedStats += primCount * instanceCount;

Just don't read from drawStripPtr/drawIndexedPtr/drawCountPtr because that pointer may be write-combined.
I'm following your suggestions but I need further help 8-)
I added a RenderSystem parameter to both renderGL3 and renderGL3V1 and also add _setFaceCount etc to RenderSystem, but:
* I don't know how to get vertex count
* In the ??? place, I don't know whether/how should I update face count.
* I know "batch count" is a bad name now, but in order to re-use the current interface, I'm increasing the batch count when setting a new Pso. Is it useful and are there other places that I should modify?

Code: Select all

 OgreMain/include/OgreRenderQueue.h  |  4 ++--
 OgreMain/include/OgreRenderSystem.h |  4 ++++
 OgreMain/src/OgreRenderQueue.cpp    | 16 ++++++++++++----
 OgreMain/src/OgreRenderSystem.cpp   | 13 +++++++++++++
 4 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/OgreMain/include/OgreRenderQueue.h b/OgreMain/include/OgreRenderQueue.h
index 6427ed2..dc3c9a4 100644
--- a/OgreMain/include/OgreRenderQueue.h
+++ b/OgreMain/include/OgreRenderQueue.h
@@ -180,12 +180,12 @@ namespace Ogre {
 
         /// Renders in a compatible way with GL 3.3 and D3D11. Can only render V2 objects
         /// (i.e. Items, VertexArrayObject)
-        unsigned char* renderGL3( bool casterPass, bool dualParaboloid,
+        unsigned char* renderGL3( RenderSystem *rs, bool casterPass, bool dualParaboloid,
                         HlmsCache passCache[],
                         const RenderQueueGroup &renderQueueGroup,
                         IndirectBufferPacked *indirectBuffer,
                         unsigned char *indirectDraw, unsigned char *startIndirectDraw );
-        void renderGL3V1( bool casterPass, bool dualParaboloid,
+        void renderGL3V1( RenderSystem *rs, bool casterPass, bool dualParaboloid,
                           HlmsCache passCache[],
                           const RenderQueueGroup &renderQueueGroup );
 
diff --git a/OgreMain/include/OgreRenderSystem.h b/OgreMain/include/OgreRenderSystem.h
index dd50098..b0c6966 100644
--- a/OgreMain/include/OgreRenderSystem.h
+++ b/OgreMain/include/OgreRenderSystem.h
@@ -912,6 +912,10 @@ namespace Ogre
         /** Reports the number of vertices passed to the renderer since the last _beginGeometryCount call. */
         virtual unsigned int _getVertexCount(void) const;
 
+		virtual void _setFaceCount(unsigned int v);
+		virtual void _setBatchCount(unsigned int v);
+		virtual void _setVertexCount(unsigned int v);
+
         /** Generates a packed data version of the passed in ColourValue suitable for
         use as with this RenderSystem.
         @remarks
diff --git a/OgreMain/src/OgreRenderQueue.cpp b/OgreMain/src/OgreRenderQueue.cpp
index decd154..d410023 100644
--- a/OgreMain/src/OgreRenderQueue.cpp
+++ b/OgreMain/src/OgreRenderQueue.cpp
@@ -441,11 +441,11 @@ namespace Ogre
                                                                     v1::CbStartV1LegacyRendering();
                     mLastVaoName = 0;
                 }
-                renderGL3V1( casterPass, dualParaboloid, mPassCache, mRenderQueues[i] );
+                renderGL3V1( rs, casterPass, dualParaboloid, mPassCache, mRenderQueues[i] );
             }
             else if( numNeededDraws > 0 /*&& mRenderQueues[i].mMode == FAST*/ )
             {
-                indirectDraw = renderGL3( casterPass, dualParaboloid, mPassCache, mRenderQueues[i],
+                indirectDraw = renderGL3( rs, casterPass, dualParaboloid, mPassCache, mRenderQueues[i],
                                           indirectBuffer, indirectDraw, startIndirectDraw );
             }
         }
@@ -543,7 +543,7 @@ namespace Ogre
         mLastTextureHash    = lastTextureHash;
     }
     //-----------------------------------------------------------------------
-    unsigned char* RenderQueue::renderGL3( bool casterPass, bool dualParaboloid, HlmsCache passCache[],
+    unsigned char* RenderQueue::renderGL3(RenderSystem *rs, bool casterPass, bool dualParaboloid, HlmsCache passCache[],
                                            const RenderQueueGroup &renderQueueGroup,
                                            IndirectBufferPacked *indirectBuffer,
                                            unsigned char *indirectDraw,
@@ -598,6 +598,9 @@ namespace Ogre
 
                 //Flush the Vao when changing shaders. Needed by D3D11/12 & possibly Vulkan
                 lastVaoName = 0;
+
+				int b = rs->_getBatchCount();
+				rs->_setBatchCount(b + 1);
             }
 
             uint32 baseInstance = hlms->fillBuffersForV2( hlmsCache, queuedRenderable, casterPass,
@@ -670,6 +673,9 @@ namespace Ogre
 
                     instanceCount = instancesPerDraw;
                 }
+				// vc???
+				int fc = rs->_getFaceCount();
+				rs->_setFaceCount(fc + vao->mPrimCount * instancesPerDraw);
 
                 lastVao = vao;
             }
@@ -679,6 +685,8 @@ namespace Ogre
                 //an external variable, as the region can be write-combined
                 instanceCount += instancesPerDraw;
                 drawCountPtr->instanceCount = instanceCount;
+
+				//????
             }
 
             ++itor;
@@ -692,7 +700,7 @@ namespace Ogre
         return indirectDraw;
     }
     //-----------------------------------------------------------------------
-    void RenderQueue::renderGL3V1( bool casterPass, bool dualParaboloid,
+    void RenderQueue::renderGL3V1( RenderSystem *rs, bool casterPass, bool dualParaboloid,
                                    HlmsCache passCache[],
                                    const RenderQueueGroup &renderQueueGroup )
     {
diff --git a/OgreMain/src/OgreRenderSystem.cpp b/OgreMain/src/OgreRenderSystem.cpp
index 7426866..76f302f 100644
--- a/OgreMain/src/OgreRenderSystem.cpp
+++ b/OgreMain/src/OgreRenderSystem.cpp
@@ -693,6 +693,19 @@ namespace Ogre {
     {
         return static_cast< unsigned int >( mVertexCount );
     }
+
+	void RenderSystem::_setFaceCount(unsigned int v) {
+		mFaceCount = v;
+	}
+
+	void RenderSystem::_setBatchCount(unsigned int v) {
+		mBatchCount = v;
+	}
+
+	void RenderSystem::_setVertexCount(unsigned int v) {
+		mVertexCount = v;
+	}
+
     //-----------------------------------------------------------------------
     void RenderSystem::convertColourValue(const ColourValue& colour, uint32* pDest)
     {


rujialiu
Goblin
Posts: 294
Joined: Mon May 09, 2016 8:21 am
x 35

Re: Get Batch and Triangle count

Post by rujialiu »

Also, when finding places to accumate face count, I found that in D3D11 VaoManager is initialized this way:

Code: Select all

mVaoManager = OGRE_NEW D3D11VaoManager( false, mDevice, this, miscParams );
So _supportsIndirectBuffers is always false. What's this?

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

Re: Get Batch and Triangle count

Post by dark_sylinc »

Your changes to get tri, face and instance count is welcomed.
However your changes are very inneficient.

Keep a counter in the stack, and at the end of the function call renderSystem->_setFaceCount & co.
Otherwise you're needlessly calling getters and setters a lot to perform a simple addition.
rujialiu wrote:
Fri Dec 13, 2019 5:31 am
Also, when finding places to accumate face count, I found that in D3D11 VaoManager is initialized this way:

Code: Select all

mVaoManager = OGRE_NEW D3D11VaoManager( false, mDevice, this, miscParams );
So _supportsIndirectBuffers is always false. What's this?
See Dx11 Indirect buffers disabled..?

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: Get Batch and Triangle count [2.2]

Post by SolarPortal »

sorry to drag up an older topic, but I recently had a go at this myself on 2.2 and got some good results from it. So thought id share my changes. Its not using setters and getters like the other persons and increases the reference counter directly and so far i have not encountered any performance changes.

Main changes are in OgreRenderQueue.cpp, in renderGL3 and renderGL3V1 more specifically.

Just added the functions directly here: (++ marks the addition)

Code: Select all

   unsigned char* RenderQueue::renderGL3( RenderSystem* renderSystem, bool casterPass, bool dualParaboloid, HlmsCache passCache[],
                                           const RenderQueueGroup &renderQueueGroup,
                                           IndirectBufferPacked *indirectBuffer,
                                           unsigned char *indirectDraw,
                                           unsigned char *startIndirectDraw )
    {
        VertexArrayObject	*lastVao = 0;
        uint32 lastVaoName = mLastVaoName;
        HlmsCache const *lastHlmsCache = &c_dummyCache;
        uint32 lastHlmsCacheHash = 0;

        int baseInstanceAndIndirectBuffers = 0;
        if( mVaoManager->supportsIndirectBuffers() )
            baseInstanceAndIndirectBuffers = 2;
        else if( mVaoManager->supportsBaseInstance() )
            baseInstanceAndIndirectBuffers = 1;

        const bool isUsingInstancedStereo = mSceneManager->isUsingInstancedStereo();
        const uint32 instancesPerDraw = isUsingInstancedStereo ? 2u : 1u;
        const uint32 baseInstanceShift = isUsingInstancedStereo ? 1u : 0u;
        uint32 instanceCount = instancesPerDraw;

        CbDrawCall *drawCmd = 0;
        CbSharedDraw    *drawCountPtr = 0;

        const QueuedRenderableArray &queuedRenderables = renderQueueGroup.mQueuedRenderables;

        QueuedRenderableArray::const_iterator itor = queuedRenderables.begin();
        QueuedRenderableArray::const_iterator end  = queuedRenderables.end();
		
++	size_t &storeInstances = renderSystem->_getInstanceCountRef();
++	size_t &storeTris = renderSystem->_getFacesCountRef();
++	size_t &storeVertices = renderSystem->_getVertexCountRef();
++	size_t &storeDraws = renderSystem->_getDrawCountRef();

        while( itor != end )
        {
            const QueuedRenderable &queuedRenderable = *itor;
            uint8 meshLod = queuedRenderable.movableObject->getCurrentMeshLod();
            const VertexArrayObjectArray &vaos = queuedRenderable.renderable->getVaos(
                        static_cast<VertexPass>(casterPass) );

            VertexArrayObject *vao = vaos[meshLod];
            const HlmsDatablock *datablock = queuedRenderable.renderable->getDatablock();

            Hlms *hlms = mHlmsManager->getHlms( static_cast<HlmsTypes>( datablock->mType ) );

            lastHlmsCacheHash = lastHlmsCache->hash;
            const HlmsCache *hlmsCache = hlms->getMaterial( lastHlmsCache,
                                                            passCache[datablock->mType],
                                                            queuedRenderable,
                                                            casterPass );
            if( lastHlmsCacheHash != hlmsCache->hash )
            {
                CbPipelineStateObject *psoCmd = mCommandBuffer->addCommand<CbPipelineStateObject>();
                *psoCmd = CbPipelineStateObject( &hlmsCache->pso );
                lastHlmsCache = hlmsCache;

                //Flush the Vao when changing shaders. Needed by D3D11/12 & possibly Vulkan
                lastVaoName = 0;
			}

            uint32 baseInstance = hlms->fillBuffersForV2( hlmsCache, queuedRenderable, casterPass,
                                                          lastHlmsCacheHash, mCommandBuffer );

            if( drawCmd != mCommandBuffer->getLastCommand() ||
                lastVaoName != vao->getVaoName() )
            {
                //Different mesh, vertex buffers or layout. Make a new draw call.
                //(or also the the Hlms made a batch-breaking command)

                if( lastVaoName != vao->getVaoName() )
                {
                    *mCommandBuffer->addCommand<CbVao>() = CbVao( vao );
                    *mCommandBuffer->addCommand<CbIndirectBuffer>() =
                                                            CbIndirectBuffer( indirectBuffer );
                    lastVaoName = vao->getVaoName();
                }

                void *offset = reinterpret_cast<void*>( indirectBuffer->_getFinalBufferStart() +
                                                        (indirectDraw - startIndirectDraw) );

                if( vao->getIndexBuffer() )
                {
                    CbDrawCallIndexed *drawCall = mCommandBuffer->addCommand<CbDrawCallIndexed>();
                    *drawCall = CbDrawCallIndexed( baseInstanceAndIndirectBuffers, vao, offset );
                    drawCmd = drawCall;
                }
                else
                {
                    CbDrawCallStrip *drawCall = mCommandBuffer->addCommand<CbDrawCallStrip>();
                    *drawCall = CbDrawCallStrip( baseInstanceAndIndirectBuffers, vao, offset );
                    drawCmd = drawCall;
                }

                lastVao = 0;

++		storeDraws += 1;
            }

            if( lastVao != vao )
            {
                //Different mesh, but same vertex buffers & layouts. Advance indirection buffer.
                ++drawCmd->numDraws;

                if( vao->mIndexBuffer )
                {
                    CbDrawIndexed *drawIndexedPtr = reinterpret_cast<CbDrawIndexed*>( indirectDraw );
                    indirectDraw += sizeof( CbDrawIndexed );

                    drawCountPtr = drawIndexedPtr;
                    drawIndexedPtr->primCount       = vao->mPrimCount;
                    drawIndexedPtr->instanceCount   = instancesPerDraw;
                    drawIndexedPtr->firstVertexIndex= vao->mIndexBuffer->_getFinalBufferStart() +
                                                                                    vao->mPrimStart;
                    drawIndexedPtr->baseVertex      = vao->mBaseVertexBuffer->_getFinalBufferStart();
                    drawIndexedPtr->baseInstance    = baseInstance << baseInstanceShift;

                    instanceCount = instancesPerDraw;
                }
                else
                {
                    CbDrawStrip *drawStripPtr = reinterpret_cast<CbDrawStrip*>( indirectDraw );
                    indirectDraw += sizeof( CbDrawStrip );

                    drawCountPtr = drawStripPtr;
                    drawStripPtr->primCount         = vao->mPrimCount;
                    drawStripPtr->instanceCount     = instancesPerDraw;
                    drawStripPtr->firstVertexIndex  = vao->mBaseVertexBuffer->_getFinalBufferStart() +
                                                                                        vao->mPrimStart;
                    drawStripPtr->baseInstance      = baseInstance << baseInstanceShift;

                    instanceCount = instancesPerDraw;
                }

                lastVao = vao;
++		storeInstances += 1;
            }
            else
            {
                //Same mesh. Just go with instancing. Keep the counter in
                //an external variable, as the region can be write-combined
                instanceCount += instancesPerDraw;
                drawCountPtr->instanceCount = instanceCount;

++				storeInstances += instancesPerDraw;
            }
			
++	    // Store the information from frame to buffer.
++	    if(renderSystem->isRecordingMetrics())
++	    {
++	    	const Ogre::OperationType &type = vao->getOperationType();
++	    	if (type == Ogre::OperationType::OT_TRIANGLE_STRIP || type == Ogre::OperationType::OT_TRIANGLE_LIST)
++	    		storeTris += (vao->mPrimCount / 3) * instancesPerDraw;
++    
++	    	storeVertices += vao->mPrimCount * instancesPerDraw;
++	    }

          ++itor;
        }

        mLastVaoName        = lastVaoName;
        mLastVertexData     = 0;
        mLastIndexData      = 0;
        mLastTextureHash    = 0;

        return indirectDraw;
    }
    //-----------------------------------------------------------------------
    void RenderQueue::renderGL3V1( RenderSystem* renderSystem, bool casterPass, bool dualParaboloid,
                                   HlmsCache passCache[],
                                   const RenderQueueGroup &renderQueueGroup )
    {
        v1::RenderOperation lastRenderOp;
        HlmsCache const *lastHlmsCache = &c_dummyCache;
        uint32 lastHlmsCacheHash = 0;

        const bool supportsBaseInstance = mVaoManager->supportsBaseInstance();

        const bool isUsingInstancedStereo = mSceneManager->isUsingInstancedStereo();
        const uint32 instancesPerDraw = isUsingInstancedStereo ? 2u : 1u;
        const uint32 baseInstanceShift = isUsingInstancedStereo ? 1u : 0u;

        uint32 instanceCount = instancesPerDraw;

        v1::CbDrawCall *drawCmd = 0;

        const QueuedRenderableArray &queuedRenderables = renderQueueGroup.mQueuedRenderables;

        QueuedRenderableArray::const_iterator itor = queuedRenderables.begin();
        QueuedRenderableArray::const_iterator end  = queuedRenderables.end();

++		size_t &storeInstances = renderSystem->_getInstanceCountRef();
++		size_t &storeTris = renderSystem->_getFacesCountRef();
++		size_t &storeDraws = renderSystem->_getDrawCountRef();
++		size_t &storeVertices = renderSystem->_getVertexCountRef();

        while( itor != end )
        {
            const QueuedRenderable &queuedRenderable = *itor;

            const HlmsDatablock *datablock = queuedRenderable.renderable->getDatablock();

            v1::RenderOperation renderOp;
            queuedRenderable.renderable->getRenderOperation(
                        renderOp, casterPass & (datablock->getAlphaTest() == CMPF_ALWAYS_PASS) );

            Hlms *hlms = mHlmsManager->getHlms( static_cast<HlmsTypes>( datablock->mType ) );

            lastHlmsCacheHash = lastHlmsCache->hash;
            const HlmsCache *hlmsCache = hlms->getMaterial( lastHlmsCache,
                                                            passCache[datablock->mType],
                                                            queuedRenderable, casterPass );
            if( lastHlmsCache != hlmsCache )
            {
                CbPipelineStateObject *psoCmd = mCommandBuffer->addCommand<CbPipelineStateObject>();
                *psoCmd = CbPipelineStateObject( &hlmsCache->pso );
                lastHlmsCache = hlmsCache;

                //Flush the RenderOp when changing shaders. Needed by D3D11/12 & possibly Vulkan
                lastRenderOp.vertexData = 0;
                lastRenderOp.indexData  = 0;
            }

            uint32 baseInstance = hlms->fillBuffersForV1( hlmsCache, queuedRenderable, casterPass,
                                                          lastHlmsCacheHash, mCommandBuffer );

            bool differentRenderOp = lastRenderOp.vertexData != renderOp.vertexData ||
                    lastRenderOp.indexData != renderOp.indexData ||
                    lastRenderOp.operationType != renderOp.operationType ||
                    lastRenderOp.useGlobalInstancingVertexBufferIsAvailable !=
                        renderOp.useGlobalInstancingVertexBufferIsAvailable;

            if( drawCmd != mCommandBuffer->getLastCommand() || differentRenderOp ||
                renderOp.numberOfInstances != 1 )
            {
                //Different mesh, vertex buffers or layout. If instanced, entities
                //likely use their own low level materials. Make a new draw call.
                //(or also the the Hlms made a batch-breaking command)

                if( differentRenderOp )
                {
                    *mCommandBuffer->addCommand<v1::CbRenderOp>() = v1::CbRenderOp( renderOp );
                    lastRenderOp = renderOp;
                }

                if( renderOp.useIndexes )
                {
                    v1::CbDrawCallIndexed *drawCall =
                            mCommandBuffer->addCommand<v1::CbDrawCallIndexed>();
                    *drawCall = v1::CbDrawCallIndexed( supportsBaseInstance );

                    /*drawCall->useGlobalInstancingVertexBufferIsAvailable =
                            renderOp.useGlobalInstancingVertexBufferIsAvailable;*/
                    drawCall->primCount         = renderOp.indexData->indexCount;
                    drawCall->instanceCount     = instancesPerDraw;
                    drawCall->firstVertexIndex  = renderOp.indexData->indexStart;
                    drawCall->baseInstance      = baseInstance << baseInstanceShift;

                    instanceCount = instancesPerDraw;

                    drawCmd = drawCall;
                }
                else
                {
                    v1::CbDrawCallStrip *drawCall =
                            mCommandBuffer->addCommand<v1::CbDrawCallStrip>();
                    *drawCall = v1::CbDrawCallStrip( supportsBaseInstance );

                    /*drawCall->useGlobalInstancingVertexBufferIsAvailable =
                            renderOp.useGlobalInstancingVertexBufferIsAvailable;*/
                    drawCall->primCount         = renderOp.vertexData->vertexCount;
                    drawCall->instanceCount     = renderOp.numberOfInstances;
                    drawCall->firstVertexIndex  = renderOp.vertexData->vertexStart;
                    drawCall->baseInstance      = baseInstance << baseInstanceShift;

                    instanceCount = instancesPerDraw;

                    drawCmd = drawCall;
                }

++				storeDraws += 1;
++				storeInstances += 1;
            }
            else
            {
                //Same mesh. Just go with instancing. Keep the counter in
                //an external variable, as the region can be write-combined
                instanceCount += instancesPerDraw;
                drawCmd->instanceCount = instanceCount;

++				storeInstances += 1;
            }

++			// Store the information from frame to buffer.
++			if (renderSystem->isRecordingMetrics())
++			{
++				if (renderOp.operationType == Ogre::OperationType::OT_TRIANGLE_STRIP || renderOp.operationType == Ogre::OperationType::OT_TRIANGLE_LIST)
++					storeTris += (renderOp.vertexData->vertexCount / 3) * instancesPerDraw;
++
++				storeVertices += renderOp.vertexData->vertexCount * instancesPerDraw;
++			}

           ++itor;
        }

        mLastVaoName        = 0;
        mLastVertexData     = 0;
        mLastIndexData      = 0;
        mLastTextureHash    = 0;
    }


Added a couple more utility functions to OgreRenderSystem.cpp, some which were there. I didnt use batch count because as you said before

CPP

Code: Select all

        , mIsRecordingMetrics(false)
        , mBatchCount(0)
        , mFaceCount(0)
        , mVertexCount(0)
	, mDrawCount(0)
	, mInstanceCount(0)

...

//-----------------------------------------------------------------------
    void RenderSystem::_beginGeometryCount(void)
    {
        mBatchCount = mFaceCount = mVertexCount = mDrawCount = mInstanceCount = 0;
    }
    //-----------------------------------------------------------------------
    unsigned int RenderSystem::_getFaceCount(void) const
    {
        return static_cast< unsigned int >( mFaceCount );
    }
    //-----------------------------------------------------------------------
    unsigned int RenderSystem::_getBatchCount(void) const
    {
        return static_cast< unsigned int >( mBatchCount );
    }    
    //-----------------------------------------------------------------------
    unsigned int RenderSystem::_getVertexCount(void) const
    {
        return static_cast< unsigned int >( mVertexCount );
    }    
    //-----------------------------------------------------------------------
    unsigned int RenderSystem::_getInstanceCount(void) const
    {
        return static_cast< unsigned int >(mInstanceCount);
    }    
	//-----------------------------------------------------------------------
	unsigned int RenderSystem::_getDrawCount(void) const
	{
		return static_cast<unsigned int>(mDrawCount);
	}
	//-----------------------------------------------------------------------
	size_t &RenderSystem::_getInstanceCountRef(void)
	{
		return mInstanceCount;
	}
	//-----------------------------------------------------------------------
	size_t &RenderSystem::_getFacesCountRef(void)
	{
		return mFaceCount;
	}
	//-----------------------------------------------------------------------
	size_t &RenderSystem::_getBatchCountRef(void)
	{
		return mBatchCount;
	}
	//-----------------------------------------------------------------------
	size_t &RenderSystem::_getVertexCountRef(void)
	{
		return mVertexCount;
	}
	//-----------------------------------------------------------------------
	size_t &RenderSystem::_getDrawCountRef(void)
	{
		return mDrawCount;
	}
H

Code: Select all

      
      
        bool mIsRecordingMetrics;
        size_t mBatchCount;
        size_t mFaceCount;
        size_t mVertexCount;
	size_t mDrawCount;
	size_t mInstanceCount;
      
      ...
      
        /** The RenderSystem will keep a count of tris rendered, this resets the count. */
        virtual void _beginGeometryCount(void);
        /** Reports the number of tris rendered since the last _beginGeometryCount call. */
        virtual unsigned int _getFaceCount(void) const;
        /** Reports the number of batches rendered since the last _beginGeometryCount call. */
	virtual unsigned int _getBatchCount(void) const;
	/** Reports the number of vertices passed to the renderer since the last _beginGeometryCount call. */
        virtual unsigned int _getVertexCount(void) const;
        /** Reports the number of vertices passed to the renderer since the last _beginGeometryCount call. */
        virtual unsigned int _getInstanceCount(void) const;
	/** Reports the number of vertices passed to the renderer since the last _beginGeometryCount call. */
        virtual unsigned int _getDrawCount(void) const;

        size_t& _getInstanceCountRef(void);
        size_t& _getDrawCountRef(void);
	size_t& _getFacesCountRef(void);
	size_t& _getBatchCountRef(void);
	size_t& _getVertexCountRef(void);
Hope this helps someone :)
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

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

Re: Get Batch and Triangle count [2.2]

Post by dark_sylinc »

SolarPortal wrote:
Sun Jun 07, 2020 2:44 pm
sorry to drag up an older topic, but I recently had a go at this myself on 2.2 and got some good results from it. So thought id share my changes. Its not using setters and getters like the other persons and increases the reference counter directly and so far i have not encountered any performance changes.
Added! Thanks for your patch!

I modified it a bit:
  1. Rather than having a ton of getters, grouped everything into getMetrics()
  2. It's more efficient to have Metrics accumulate in the stack, then add everything at the end. This is because references force the compile on a slow path, because it must assume the variable could've changed between calls to code it cannot see. Thus it's always "load-increment-store", without even being able to coalesce loads or stores
  3. I'm not sure what's the objective of mIsRecordingMetrics, you were only using it to not record vertex & tri count. I set it to not record everything (functionally not equivalent) and the boolean is evaluated at the end rather than per iteration, in RenderSystem::_addMetrics

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: Get Batch and Triangle count

Post by SolarPortal »

Brilliant :)
I'm not sure what's the objective of mIsRecordingMetrics,
Simply to stop recording of metrics to make it a little bit faster at the expense of one conditional check. The reason i didnt include the others because they were lightweight enough and it would have taken more checks on those seperate pieces.

Thanks for the tips too :)
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

Post Reply