Index Buffers

Index buffers, represented by the IDirect3DIndexBuffer9 interface, are memory buffers that contain index data. Index data, or indices, are integer offsets into vertex buffers and are used to render primitives using the IDirect3DDevice9::DrawIndexedPrimitive method.

A vertex buffer contains vertices; therefore, you can draw a vertex buffer either with or without indexed primitives. However, because an index buffer contains indices, you cannot use an index buffer without a corresponding vertex buffer. (As a side note, IDirect3DDevice9::DrawIndexedPrimitiveUP and IDirect3DDevice9::DrawPrimitiveUP are the only draw methods that draw without an index or a vertex buffer.)

Index Buffer Description

An index buffer is described in terms of its capabilities, such as where it exists in memory, whether it supports reading and writing, and the type and number of indices it can contain. These traits are held in a D3DINDEXBUFFER_DESC structure.

Index buffer descriptions tell your application how an existing buffer was created. You provide an empty description structure for the system to fill with the capabilities of a previously created index buffer.

Index Processing Requirements

The performance of index processing operations depends heavily on where the index buffer exists in memory and what type of rendering device is being used. Applications control the memory allocation for index buffers when they are created. When the D3DPOOL_SYSTEMMEM memory flag is set, the index buffer is created in system memory. When the D3DPOOL_DEFAULT memory flag is used, the device driver determines where the memory for the index buffer is best allocated, often referred to as driver-optimal memory. Driver-optimal memory can be local video memory, non-local video memory, or system memory.

Setting the D3DUSAGE_SOFTWAREPROCESSING behavior flag when calling the IDirect3DDevice9::CreateIndexBuffer method specifies that the index buffer is to be used with software vertex processing. This flag is required in mixed mode vertex processing (D3DCREATE_MIXED_VERTEXPROCESSING) when software vertex processing is used.

The application can directly write indices to a index buffer allocated in driver-optimal memory. This technique prevents a redundant copy operation later. This technique does not work well if your application reads data back from an index buffer, because read operations done by the host from driver-optimal memory can be very slow. Therefore, if your application needs to read during processing or writes data to the buffer erratically, a system-memory index buffer is a better choice.

Note    Always use D3DPOOL_DEFAULT, except when you don't want to use video memory or use large amounts of page-locked RAM when the driver is putting vertex or index buffers into AGP memory.

Create an Index Buffer

Create an index buffer object by calling the IDirect3DDevice9::CreateIndexBuffer method, which accepts six parameters.

The following C++ code example shows what creating an index buffer might look like in code.

/*
 * For the purposes of this example, the d3dDevice variable is the 
 * address of an IDirect3DDevice9 interface exposed by a 
 * Direct3DDevice object, g_IB is a variable of type 
 * LPDIRECT3DINDEXBUFFER9.
 */

if( FAILED( d3dDevice->CreateIndexBuffer( 16384 *sizeof(WORD),
           D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, 
	       &g_IB, NULL ) ) )
    return E_FAIL;

Access an Index Buffer

Index buffer objects enable applications to directly access the memory allocated for index data. You can retrieve a pointer to index buffer memory by calling the IDirect3DIndexBuffer9::Lock method, and then accessing the memory as needed to fill the buffer with new index data or to read any data it contains. The Lock method accepts four parameters. The first, OffsetToLock, is the offset into the index data. The second parameter is the size, measured in bytes, of the index data. The third parameter accepted by the IDirect3DIndexBuffer9::Lock method, ppbData, is the address of a BYTE pointer filled with a pointer to the index data, if the call succeeds.

The last parameter, Flags, tells the system how the memory should be locked. You can use it to indicate how the application accesses the data in the buffer. Specify constants for the Flags parameter according to the way the index data will be accessed by your application. This allows the driver to lock the memory and provide the best performance given the requested access type. Use D3DLOCK_READONLY flag if your application will read only from the index buffer memory. Including this flag enables Direct3D to optimize its internal procedures to improve efficiency, given that access to the memory will be read-only.

After you fill or read the index data, call the IDirect3DIndexBuffer9::Unlock method, as shown in the following code example.

// This code example assumes the m_pIndexBuffer is a variable of type 
// LPDIRECT3DINDEXBUFFER9 and that g_Indices has been properly 
// initialized with indices.

// To fill the index buffer, you must lock the buffer to gain 
// access to the indices. This mechanism is required because index
// buffers may be in device memory.

VOID* pIndices;

if( FAILED( m_pIndexBuffer->Lock( 
      0,                 // Fill from start of the buffer
      sizeof(g_Indices), // Size of the data to load
      BYTE**)&pIndices,  // Returned index data
      0 ) ) )            // Send default flags to the lock
{
    SAFE_RELEASE(m_pIndexBuffer);
    return E_FAIL;
}

memcpy( pIndices, g_Indices, sizeof(g_Indices) );
m_pIndexBuffer->Unlock();

Note    

If you create an index buffer with the D3DUSAGE_WRITEONLY flag, do not use the D3DLOCK_READONLY locking flag. Use the D3DLOCK_READONLY flag if your application will read only from the index buffer memory. Including this flag enables Direct3D to optimize its internal procedures to improve efficiency, given that access to the memory will be read-only.

For information about using D3DLOCK_DISCARD or D3DLOCK_NOOVERWRITE for the Flags parameter of the IDirect3DIndexBuffer9::Lock method, see Performance Optimizations.

In C++, because you directly access the memory allocated for the index buffer, make sure your application properly accesses the allocated memory. Otherwise, you risk rendering that memory invalid. Use the stride of the index format your application uses to move from one index in the allocated buffer to another.

Retrieve information about an index buffer by calling the IDirect3DIndexBuffer9::GetDesc method. This method fills the members of the D3DINDEXBUFFER_DESC structure with information about the vertex buffer.

See Also

Rendering from Vertex and Index Buffers, Vertex Buffers