Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

batching? how?

Started by eschan01 Jan 26, 2008 at 5:14 PM 8 replies 1.8k views
Original Post
eschan01
eschan01
I've been searching and reading many threads that discuss about batching. The basic concept - group and draw things together that share the same render states - seems simple enough. But, I don't see how I can make this work. Hope someone here can shed some light on this. Let's say I have n objects I'm drawing individually (d3d drawprimitive calls, and this is really slowing down the frame rate a lot as n gets bigger). They're all shaded with the same shaders, and they all have the same textures. The only difference between each one is that they have a different world transform. The world transform, among other things, are passed into the shaders. I'd like to batch all these objects together and only call drawprimitive once, but the world transform alone is making this impossible (I think.) One possible way I see making this work is to factor out all the stuff that are not common to the objects. Do the calculation on the CPU, and then write the result (vertices) into the vertex buffer. But, this seems like a bad idea (?) since doing things on the CPU might be slower than actually calling drawprimitive many times. I'm also not really sure if the factorization is always possible. And, it just doesn't seem to make sense that I'd be forced to apply transforms to the objects in software rather than giving the transforms to the GPU to deal with. I'm really stumped. How is it possible to batch similar objects together when something fundamental like the world transform gets in the way? I think I'm missing some important idea that would make batching work.
silvermace
silvermace
What you describe is not batching in the traditional sense. When you batch, it is usually simply to avoid the state CHANGES, this means that calling your API's low level draw command multiple times is okay. As ToohrVyk has mentioned, it would be even more performant (AFAIK) to use geometry instancing if your hardware supports it.

my pseudo code:
list< RenderableObject > items;items.sortByMaterials();foreach obj in items {  if( previousItem.material != obj.material )      obj.material.bind(); // only bind a new material if its different to the one current set in the driver  driver.setTransform( obj.transform );  driver.drawBuffer( obj.vertexBuffer, obj.indexBuffer );}
that is a very very basic example, but you should get the idea...
eschan01
eschan01
Oh hmm. Thanks! Guess I've been looking into the wrong idea.

Question still. Instancing is fairly new (a few years?) isn't it? Does this mean older games had never implemented batching?
eschan01
eschan01
Quote:
Original post by silvermace
What you describe is not batching in the traditional sense. When you batch, it is usually simply to avoid the state CHANGES, this means that calling your API's low level draw command multiple times is okay.


I see. Batching isn't really what I'm looking for. I think I get it now.

Although, even with no state changes in between each draw call, I'm seeing a significant performance hit when calling d3d drawprimitive a few hundred times per frame (maybe it's just d3d specific issue).

Thank you both for the information.
silvermace
silvermace
I'm an OpenGL programmer so I'm not too familiar with D3D, AFAIK DrawPrimitveUP is the slow one? and if you're drawing a few hundred (~400) meshes, I think you're going see a performance hit anyway, no? In OpenGL one would use things such as vertex buffer objects/display lists and smaller index format (e.g. 16 bit unsigned over 32 bit signed) and also try to optimise for your video cards cache's. Just be careful that you are not optimising prematurely.
Cranny76
Cranny76
Also check how your creating your device. Sometime you might think you're creating it using hardware vertex processing, only to find out it defaulted back to software.

Other then that, if you're using the debug runtime of DirectX, go to the control panel and scale back the error output. This can really slow your frame rate down.
ViLiO
ViLiO
Quote:
Original post by eschan01
Question still. Instancing is fairly new (a few years?) isn't it? Does this mean older games had never implemented batching?
For what you describe of having a bunch of models sharing same material but only differing in their transform, on older hardware you could just transform the verts to world space on the CPU, lock and fill a dynamic VB/IB with them and render the lot with a single draw call (or with a few draw calls so as not to go beyond what 16bit indices can index).

Regards,
ViLiO
Richard 'ViLiO' Thomasv.net | Twitter | YouTube
jbarcz1
jbarcz1
Quote:
Original post by eschan01
Quote:
Original post by silvermace
What you describe is not batching in the traditional sense. When you batch, it is usually simply to avoid the state CHANGES, this means that calling your API's low level draw command multiple times is okay.


Although, even with no state changes in between each draw call, I'm seeing a significant performance hit when calling d3d drawprimitive a few hundred times per frame (maybe it's just d3d specific issue).


How are you testing this, and what is your performance 'hit' relative to? Did you try drawing only the first triangle in each mesh to rule out vertex bottlenecks, or are you just drawing 400 copies of the mesh with the same state? If you're drawing large meshes with DrawPrimitive, instead of DrawIndexedPrimitive with optimized index buffers, then you might very well have a vertex throughput problem.
Joshua Barczak3D Application Research GroupAMD

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.