This sample demonstrates the instancing feature available with Direct3D 9. A vs_3_0 device is required for the hardware version of this feature. The sample also shows alternate ways of achieving results similar to hardware instancing, but for adapters that do not support vs_3_0. The shader instancing technique shows the benefits of efficient batching of primitives.
How the Sample Works
The sample demonstrates four different rendering techniques to achieve the same result: to render many nearly identical boxes (objects with small numbers of polygons) in the scene. The boxes differ by their position and color.
The user can vary the number of boxes in the scene between one and 1000. Use the sample to monitor performance as the number of boxes increases. As you change the number of boxes, the vertex and index buffer resources are recreated by OnCreateBuffers and OnDestroyBuffers.
Technique 1: Hardware Instancing
Hardware instancing requires a vs_3_0-capable device. The instance-specific data is stored in a second vertex buffer. The rendering is implemented in the sample application's OnRenderHWInstancing method. IDirect3DDevice9::SetStreamSourceFreq is used with D3DSTREAMSOURCE_INDEXEDDATA to specify the number of boxes and with D3DSTREAMSOURCE_INSTANCEDATA to specify the frequency of the instance data (in this case, frequency equals one).
This is the most efficient technique that does not use the hardware to perform the instancing. One call to IDirect3DDevice9::DrawIndexedPrimitive handles multiple primitives at once. The instance data is stored in a system memory array, which is then copied into the vertex shader's constants at draw time. Since vs_2_0 only guarantees 256 constants, it is not possible for the entire array of instance data to fit at once. This sample's .fx file can only batch-process 120 constants (one float4 is required for box position, and one float4 is required for box color). Rendering is performed in the sample's OnRenderShaderInstancing method.
This method would also work on a vs_1_1 part, although not as efficiently because vs_1_1 only guarantees 96 constants. This means that batching is nearly three times more efficient on vs_2_0 hardware than on vs_1_1 hardware, but even on vs_1_1 hardware, batching still outperforms no batching.
This technique is somewhat similar to Technique 2 without the batching (batch size = 1). It will render one box at a time, by first setting its position and color and then calling DrawIndexedPrimitive. The technique is implemented in the sample's OnRenderConstantsInstancing method.
Technique 4: Stream Instancing
As in Technique 1, this technique uses a second vertex buffer to store instance data. Instead of setting vertex shader constants to update the position and color for each box, this technique changes the offset in the instance stream buffer and draws one box at a time. The technique is implemented in the sample's OnRenderStreamInstancing method.
CPU- vs. GPU-bound
When the sample renders a large number of boxes, only Techniques 1 and 2 are GPU-bound, while Techniques 3 and 4 waste many CPU cycles by making numerous calls per frame to DrawIndexedPrimitive.
The performance numbers for rendering a large number of boxes show that only the first two techniques are GPU-bound, while the last two techniques waste a lot of CPU cycles by making numerous calls to DrawIndexedPrimitive per frame. To better illustrate the penalty from being CPU-bound in a real world application, the sample has the Goal option which simulates a secondary task (in a game, this could be AI or physics) competing for CPU. The sample queries the time elapsed since the last frame and if there is time remaining inside the goal time/frame, the sample allows time to pass to represent game logic. It reports the amount of time used in the Remaining for logic statistic. This is the percentage of CPU cycles that are available to spend on non-rendering algorithms such as game logic or physics; the higher the percentage, the better. If the scene is loaded with 1000 boxes, it was observed that the efficient techniques have 2x better CPU efficiency than the CPU-bound techniques. In other words, using Techniques 3 and 4 to render many instances will starve other tasks of CPU time.
The following table summarizes hardware and memory requirements for different rendering techniques:
하드웨어 인스턴싱
하드웨어 인스턴싱은 정점 셰이더 3.0을 지원하는 그래픽카드가 필요하다. 하드웨어 인스턴싱은 특정한 인스턴싱 데이터가 세컨드 정점버퍼에 들어가게 된다. 샘플의 OnRenderHWInstancing 함수를 통해 구현된다.
여기서 IDirect3DDevice9::SetStreamSourceFreq 함수가 상자 수를 지정하기 위한 매크로 상수 D3DSTREAMSOURCE_INDEXEDDATA, 인스턴스 데이터의 주기를 지정하기 위한 매크로 상수 D3DSTREAMSOURCE_INSTANCEDATA가 함께 사용된다. (이 경우에 , 빈도는 1이다.)
드로우 함수
로 장면이 출력된다.
셰이더 인스턴싱 (Draw Call Batching 사용)
하드웨어를 사용하지 않는 가장 효율적인 인스턴싱 기법이다. IDirect3DDevice9::DrawIndexedPrimitive 함수는 여러 프리미티브(점, 선, 폴리곤, 렌더링 최소단위)를 한번에 (인덱스 버퍼 내에 지정한 만큼) 처리한다. 인스턴스 데이터는 시스템 메모리에 저장되어 드로우 타임에 버텍스 셰이더에 상수에 복사된다.
(시스템 메모리는 RAM 일 수 있고 V-RAM 일 수 있다)
버텍스 셰이더 2.0은 256개의 상수만 보장하기 때문에 전체 인스턴스 데이터의 감당이 불가능하다.
예제 샘플의 fx파일은 120개의 상수만 처리가 가능하다. 상자 위치뿐만 아니라 색상까지 포함해 두개의 float4가 필요하기 때문에 절반의 용량이 날라간다
OnRenderShaderInstancing 메서드에서 수행된다
이러한 방식은 버텍스 셰이더 1.1버전에서도 작동하지만 최대 96개의 상수만 담을 수 있고, 이 때문에 효율적이진 않다. 그러나 이 기법을 사용해야 할 때 쓰지 않는 것보단 쓰는게 효율이다.
상수 인스턴싱 (Draw Call Batching 사용 안함)
해당 방식은 Batching을 사용하지 않은 셰이더 인스턴싱과 비슷하다(배치 사이즈가 1이다).
이러한 방식은 위치, 색상을 먼저 설정하고 DrawIndexedPrimitive 함수를 통해 박스를 한 번에 하나씩 렌더링한다.
OnRenerConstantsInstancing 함수에서 볼 수 있다.
스트림 인스턴싱
하드웨어 인스턴싱은 인스턴스 데이터를 세컨드 버텍스 버퍼에 담는 방식으로 구현되었다. 정점 셰이더 상수로 데이터의 위치, 색상값을 각각의 박스(모델)마다 갱신하던 반면에, 스트림 인스턴싱은 인스턴스 스트림 버퍼의 오프셋을 변경하고 한번에 하나씩 박스를 그린다.
CPU- 대 GPU 바인딩
샘플이 많은 수의 박스를 렌더링할 때 매개 변수 1과 2만 GPU로 바인딩된 반면 매개 변수 3과 4는 프레임당 수많은 DrawIndexedPrimitive 함수 호출로 하여 많은 CPU 사이클을 낭비한다.
많은 수의 박스를 렌더링하는 동안, 퍼포먼스 결과는 처음 두 기법만이 GPU-bound인 반면, 마지막 두 기법은 프레임당 수많은 DrawIndexedPrimitive 호출을 함으로써 많은 CPU 사이클을 낭비한다는 것을 보여준다.
실제 애플리케이션에서 CPU 바인딩으로 인한 손실을 더 잘 설명하기 위해 샘플에는 CPU자원을 더 긁어대기 위한 보조 작업(게임에서 AI 또는 물리)을 시뮬레이션하는 추가적인 옵션이 존재한다.
[ 샘플은 마지막 프레임 이후 경과된 시간을 쿼리하고, 골 시간/프레임 내에 남은 시간이 있을 경우 샘플은 게임 논리를 나타낼 수 있는 시간을 허용한다.
그것은 논리 통계에 대해 남은 시간 통계에 사용된 시간을 보고한다.
이는 게임 논리나 물리학과 같은 비렌더링 알고리즘에 사용할 수 있는 CPU 사이클의 비율이며, 비율이 높을수록 좋다.
씬(scene)이 1000박스로 로드되면 효율적인 기법이 CPU 바인딩 기법보다 2배 높은 CPU 효율을 갖는다는 것이 관찰됐다.
즉, 매개 변수 3과 4를 사용하여 많은 인스턴스를 렌더링하면 CPU 시간의 다른 작업이 중단된다.
다음 표에는 다양한 렌더링 기법에 대한 하드웨어 및 메모리 요구 사항이 요약되어 있다. ] - 파파고