Draw call optimization for multiple meshes in DirectX11

I have a large scene in a B3D model, which includes about 120 meshes as in the following pictures:

large B3D scene http://s22.postimg.org/d1h75hr0v/Untitled.png

Each mesh contain a vertex buffer and material information such as diffuse, specular, ambient...

I'm using Directx 11 for rendering, and it takes me about 120 IndexedDraw calls per frame, and the frame rate is down to 30f/s. This speed is so slow and I can't apply physics to the application.

Now I want to group these IndexedDraw call into only one DrawCall per frame. To do this, I'm thinking about creating multiple vertex buffers in Directx, and each of these will own its own material information. For each draw call, DirectX will loop over such vertex buffers and pass the corresponding material information.

I want to ask you there's any way to do this in DirectX11, and if not, could you please suggest me some way to optimize my application.

Detail information of IndexedDraw calls.

    19 ID3D11DeviceContext::DrawIndexed(5898,0,0)
25 ID3D11DeviceContext::DrawIndexed(20664,0,0)
31 ID3D11DeviceContext::DrawIndexed(3000,0,0)
37 ID3D11DeviceContext::DrawIndexed(5340,0,0)
43 ID3D11DeviceContext::DrawIndexed(3540,0,0)
51 ID3D11DeviceContext::DrawIndexed(2760,0,0)
59 ID3D11DeviceContext::DrawIndexed(3444,0,0)
65 ID3D11DeviceContext::DrawIndexed(1680,0,0)
71 ID3D11DeviceContext::DrawIndexed(1680,0,0)
79 ID3D11DeviceContext::DrawIndexed(72,0,0)
85 ID3D11DeviceContext::DrawIndexed(1920,0,0)
91 ID3D11DeviceContext::DrawIndexed(1332,0,0)
97 ID3D11DeviceContext::DrawIndexed(618,0,0)
105 ID3D11DeviceContext::DrawIndexed(720,0,0)
111 ID3D11DeviceContext::DrawIndexed(6,0,0)
117 ID3D11DeviceContext::DrawIndexed(174,0,0)
123 ID3D11DeviceContext::DrawIndexed(360,0,0)
129 ID3D11DeviceContext::DrawIndexed(78,0,0)
137 ID3D11DeviceContext::DrawIndexed(1368,0,0)
143 ID3D11DeviceContext::DrawIndexed(324,0,0)
151 ID3D11DeviceContext::DrawIndexed(900,0,0)
157 ID3D11DeviceContext::DrawIndexed(216,0,0)
165 ID3D11DeviceContext::DrawIndexed(900,0,0)
171 ID3D11DeviceContext::DrawIndexed(216,0,0)
179 ID3D11DeviceContext::DrawIndexed(900,0,0)
185 ID3D11DeviceContext::DrawIndexed(216,0,0)
193 ID3D11DeviceContext::DrawIndexed(504,0,0)
199 ID3D11DeviceContext::DrawIndexed(6,0,0)
205 ID3D11DeviceContext::DrawIndexed(174,0,0)
211 ID3D11DeviceContext::DrawIndexed(360,0,0)
217 ID3D11DeviceContext::DrawIndexed(78,0,0)
225 ID3D11DeviceContext::DrawIndexed(108,0,0)
231 ID3D11DeviceContext::DrawIndexed(24,0,0)
239 ID3D11DeviceContext::DrawIndexed(900,0,0)
245 ID3D11DeviceContext::DrawIndexed(216,0,0)
253 ID3D11DeviceContext::DrawIndexed(108,0,0)
259 ID3D11DeviceContext::DrawIndexed(24,0,0)
267 ID3D11DeviceContext::DrawIndexed(144,0,0)
273 ID3D11DeviceContext::DrawIndexed(504,0,0)
279 ID3D11DeviceContext::DrawIndexed(6,0,0)
285 ID3D11DeviceContext::DrawIndexed(174,0,0)
291 ID3D11DeviceContext::DrawIndexed(360,0,0)
296 ID3D11DeviceContext::DrawIndexed(78,0,0)
304 ID3D11DeviceContext::DrawIndexed(372,0,0)
310 ID3D11DeviceContext::DrawIndexed(30,0,0)
316 ID3D11DeviceContext::DrawIndexed(360,0,0)
321 ID3D11DeviceContext::DrawIndexed(78,0,0)
327 ID3D11DeviceContext::DrawIndexed(144,0,0)
335 ID3D11DeviceContext::DrawIndexed(108,0,0)
341 ID3D11DeviceContext::DrawIndexed(24,0,0)
349 ID3D11DeviceContext::DrawIndexed(540,0,0)
355 ID3D11DeviceContext::DrawIndexed(540,0,0)
363 ID3D11DeviceContext::DrawIndexed(5322,0,0)
369 ID3D11DeviceContext::DrawIndexed(540,0,0)
377 ID3D11DeviceContext::DrawIndexed(792,0,0)
385 ID3D11DeviceContext::DrawIndexed(1800,0,0)
393 ID3D11DeviceContext::DrawIndexed(540,0,0)
399 ID3D11DeviceContext::DrawIndexed(540,0,0)
407 ID3D11DeviceContext::DrawIndexed(36,0,0)
413 ID3D11DeviceContext::DrawIndexed(36,0,0)
420 ID3D11DeviceContext::DrawIndexed(36,0,0)
428 ID3D11DeviceContext::DrawIndexed(450,0,0)
436 ID3D11DeviceContext::DrawIndexed(36,0,0)
442 ID3D11DeviceContext::DrawIndexed(36,0,0)
449 ID3D11DeviceContext::DrawIndexed(36,0,0)
456 ID3D11DeviceContext::DrawIndexed(36,0,0)
464 ID3D11DeviceContext::DrawIndexed(396,0,0)
470 ID3D11DeviceContext::DrawIndexed(396,0,0)
476 ID3D11DeviceContext::DrawIndexed(396,0,0)
482 ID3D11DeviceContext::DrawIndexed(396,0,0)
488 ID3D11DeviceContext::DrawIndexed(396,0,0)
494 ID3D11DeviceContext::DrawIndexed(396,0,0)
500 ID3D11DeviceContext::DrawIndexed(396,0,0)
506 ID3D11DeviceContext::DrawIndexed(396,0,0)
512 ID3D11DeviceContext::DrawIndexed(396,0,0)
518 ID3D11DeviceContext::DrawIndexed(396,0,0)
524 ID3D11DeviceContext::DrawIndexed(396,0,0)
530 ID3D11DeviceContext::DrawIndexed(396,0,0)
536 ID3D11DeviceContext::DrawIndexed(396,0,0)
544 ID3D11DeviceContext::DrawIndexed(1512,0,0)
548 ID3D11DeviceContext::DrawIndexed(1512,0,0)
556 ID3D11DeviceContext::DrawIndexed(78,0,0)
562 ID3D11DeviceContext::DrawIndexed(540,0,0)
568 ID3D11DeviceContext::DrawIndexed(36,0,0)
576 ID3D11DeviceContext::DrawIndexed(78,0,0)
582 ID3D11DeviceContext::DrawIndexed(360,0,0)
588 ID3D11DeviceContext::DrawIndexed(24,0,0)
596 ID3D11DeviceContext::DrawIndexed(180,0,0)
602 ID3D11DeviceContext::DrawIndexed(12,0,0)
608 ID3D11DeviceContext::DrawIndexed(624,0,0)
616 ID3D11DeviceContext::DrawIndexed(180,0,0)
622 ID3D11DeviceContext::DrawIndexed(12,0,0)
628 ID3D11DeviceContext::DrawIndexed(624,0,0)
636 ID3D11DeviceContext::DrawIndexed(180,0,0)
642 ID3D11DeviceContext::DrawIndexed(12,0,0)
648 ID3D11DeviceContext::DrawIndexed(624,0,0)
656 ID3D11DeviceContext::DrawIndexed(180,0,0)
662 ID3D11DeviceContext::DrawIndexed(12,0,0)
668 ID3D11DeviceContext::DrawIndexed(624,0,0)
676 ID3D11DeviceContext::DrawIndexed(180,0,0)
682 ID3D11DeviceContext::DrawIndexed(12,0,0)
690 ID3D11DeviceContext::DrawIndexed(864,0,0)
698 ID3D11DeviceContext::DrawIndexed(648,0,0)
704 ID3D11DeviceContext::DrawIndexed(648,0,0)
710 ID3D11DeviceContext::DrawIndexed(648,0,0)
718 ID3D11DeviceContext::DrawIndexed(216,0,0)
726 ID3D11DeviceContext::DrawIndexed(180,0,0)
732 ID3D11DeviceContext::DrawIndexed(12,0,0)
740 ID3D11DeviceContext::DrawIndexed(180,0,0)
746 ID3D11DeviceContext::DrawIndexed(12,0,0)
754 ID3D11DeviceContext::DrawIndexed(180,0,0)
760 ID3D11DeviceContext::DrawIndexed(12,0,0)
766 ID3D11DeviceContext::DrawIndexed(624,0,0)
774 ID3D11DeviceContext::DrawIndexed(180,0,0)
780 ID3D11DeviceContext::DrawIndexed(12,0,0)
786 ID3D11DeviceContext::DrawIndexed(624,0,0)


• 120 batches per frame is not enough to be the limiting factor in performance. If you're only getting 30 fps at this point it's because of something else - likely the number of vertices and/or pixels. Switching to indexed draws is not likely to help your performance at all. – Nathan Reed May 12 '14 at 2:41
• The picture you've attached is not showing, btw. – glampert May 12 '14 at 2:41
• @NathanReed, glampert: I have updated the question to provide the detail information about the indexedDrawCall. Whether in this case the number of vertex is the reason for this 30fps speed? – khanhhh89 May 12 '14 at 4:02
• Summing your vertex counts gives 92K vertices in all which doesn't seem like that much. What hardware are you running this on? If it's an mobile/integrated GPU, or an older one, it might just not have the horsepower to handle that many verts. It doesn't look like you're doing complex shading so I wouldn't think pixel throughput would be the issue. Or maybe the issue is something completely different in the engine. – Nathan Reed May 12 '14 at 19:41
• I would sort them on geometry(mesh) and call the DrawIndexedInstanced not using a additional Instance vertex buffer, but storing the matrices/material in a StructuredBuffer<T>. And defining a unsigned int InstanceId : SV_InstanceID; in the VertexIn struct of the HLSL. With these reference words, you're able to find some examples. – Jeroen van Langen Feb 8 '17 at 10:15

A modern gpu can easily handle around 3k Drawcalls ( This is well optimized of course ) and most likely even 2k with out any superb optimization. So I´m assume your FPS is down due to some CPU Bottleneck that's happening. ( could be related to rendering )

And to answer your question. One smart way of storing your Mesh to a compact and well optimized vertexbuffer for the cost of some extra memory and bandwidth is to combine all of it´s static values to vertex data. you specificly dont need to interpolate the data on the gpu later to get accurate values. So in general the vertex layout could be like this :

float4 positionXYZ,AmbientScale( could be anything )
float4 normalXYZ,SpecularScale( could be anything )
float4 uvcordsUV,ExtraLightBakedUV( could be anything )


What happens here is that you are packing your stuff into the vertex data which will always remain the same. You could basically pack what ever you want into this vertex layout. And it will most likely be faster than having more vertex buffers to iterate over.

• I used the profiler Sleepy to analyze the running time, and it turns out that the IndexedDraw call take a little of time, as you said. But I think the problem is not only about the IndexedDraw call, but also other DirectX11 API for setting pipeline states. I'm using the engine Hieroglyph (hieroglyph3.codeplex.com), which use pipeline state monitoring for setting such states, which is discussed in the article: gamedev.net/blog/411/entry-2256152-pipeline-state-monitoring. Do you have any ideas about this engine? – khanhhh89 May 12 '14 at 14:57
• I have followed the guy for a while. and he is a experianced coder so i doubt that his engine is going to give you that kind of peformance. Rather try to profile everystep of your code. How many triangles are you rendering in total? if you could update your image to a wireframe renderer that would be greate. – Tordin May 13 '14 at 7:29
• It's about 30.770 triangles per frame. I posted the question on the Hieroglyph3 website, if you have time, please take a look at it for me.By the way, could you suggest me some graphics engine in DirectX11 except Ogre, Irrlicht. Thanks so much! – khanhhh89 May 13 '14 at 8:01
• Well, I always write my frameworks myself. It don't take too long. and you get pretty good experience from it. Unless you are interested in doing something else of course. What is it you are trying todo? – Tordin May 13 '14 at 8:03
• Actually, it´s not so that there is a FPS clamp in the engine itself when you are rendering stuff? Because it´s very common to render frames in 30fps. – Tordin May 13 '14 at 8:06