Asteroids

This sample is designed to be a performance benchmark and is based on this demo developed by Intel. It renders 50,000 unique textured asteroids. Every asteroid is a combination of one of 1000 unique meshes and one of 10 unique textures. The sample uses original D3D11 and D3D12 native implementations, and adds implementation using Diligent Engine API to allow comparing performance of different rendering modes.
AsteroidsDemo3

Building and Running the Sample

The full sample source code is available at GitHub. To build the sample, download the engine, and open EngineAll.sln solution in build\Win32 folder. Asteroids demo only supports x64 platform. Set Asteroids project as the startup project and run it.

Controls

The sample uses the following keys:

  • ‘1’ – switch to native D3D11 mode
  • ‘2’ – switch to native D3D12 mode
  • ‘3’ – switch to Diligent D3D11 mode
  • ‘4’ – switch to Diligent D3D12 mode
  • ‘M’ – toggle multithreaded rendering
  • ‘+’ – increment number of threads
  • ‘-‘ – decrement number of threads

Implementation Details

Main loop of the sample consists of two parts: update and render. The fist part performs simulation of asteroid movement and is not related to graphics API. The second part is where all API-specific commands are executed. The application displays total frame time, update time and render time in the title bar:

AsteroidsDemoTimeCounters2
The application is intentionally CPU-bound as its goal is to analyze CPU-side efficiency of different graphics APIs. Most of the time render function spends handling 50,000 asteroids. It also renders background and text sprites, but these steps take negligible fraction of total time and are ignored.

Native D3D11 Implementation

The main part of the native D3D11 render routine first sets all the required states (vertex and index buffers, shaders, rasterizer, blend and depth-stencil states etc.) and then iterates over all 50,000 asteroids. For every object, the function does the following:

  • Maps dynamic constant buffer and uploads attributes of the current object
  • Sets object’s texture as PS shader resource
  • Calls draw command

The asteroid rendering loop is given in the listing below:

Native D3D12 Implementation

The main part of the native D3D12 render routine uses dynamic resource indexing feature available in D3D12. It lets the shaders dynamically select the resource in run time. For this particular example, the demo selects asteroid texture right in the shader as shown in the code snippet below:

Note that mTextureIndex comes from the constant buffer, which was not allowed in PS5.0 or earlier versions. The render routine sets pipeline state and root signature, binds all textures and then iterates over all 50,000 asteroids. For every object, it sets constant buffer view and runs draw command. The asteroid rendering loop is given in the listing below:

Diligent Engine Implementation

As Diligent Engine does not operate with shader registers directly, but uses shader resource binding objects, there are several ways main render loop can be implemented. The sample implements three modes:

  • Dynamic. In this mode, asteroid texture is marked as dynamic resource, and there is single SRB object. For every asteroid, its texture is first bound to the shader variable in the SRB object, and SRB resources are committed to the GPU pipeline.
  • Mutable. In this mode, asteroid texture is marked as mutable resource, and there are 50,000 SRB objects, one for every asteroid. The texture is bound only once to every SRB object during the initialization.
  • Texture Mutable. In this mode, asteroid texture is marked also as mutable resource, but there are only 10 SRB objects, one for every unique texture. The texture is bound only once to every SRB object during the initialization. Also, since there are only 10 SRB objects, they can be first transitioned to correct states before the loop and then committed without COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag to avoid unnecessary operations.

The following listing shows the asteroid rendering loop implemented using the Diligent Engine API:

The default mode is Texture Mutable and can be changed by assigning different value to the AsteroidsDE::Asteroids::m_BindingMode variable.