7 Xbox D3D drawing via NV2A Kelvin
PatrickvL edited this page 2021-07-12 18:33:03 +02:00

Xbox D3D drawing is performed via 4 Draw*Vertices* APIs (and a few other cases, described below);

All 4 Draw*Vertices* APIs have the two arguments (D3DPRIMITIVETYPE PrimitiveType, UINT VertexCount). Additionally:

  • One API has a StartVertex argument
  • Two draw using indices, and for that have an additional "index data" argument
  • Two draw using a 'User Pointer', and for that have additional "stream zero" arguments

The vertex data required for drawing, is either read from up to 16 VertexBuffers (as set by the SetStreamSource API), or for the User Pointer (UP) draws, read directly from the supplied Stream Zero pointer (and stride).

Vertex data is composed of 1 up to 16 attributes, as defined in a vertex declaration. Each attribute declaration specifies the StreamSource index from which the attribute data is read. (User Pointer draws are only allowed to read from stream index zero, which will use the supplied pointer, not actually stream zero!)

The order vertices are drawn in, is either:

  • sequential, for regular draws (starting at the first vertex, or for DrawVertices at the specified StartVertex offset into the vertex buffer),
  • or according to the specified pIndexData (which allows re-using vertices and drawing subsets of available vertices in the given buffer)
    Xbox D3D API                    Arguments (D3DPRIMITIVETYPE PrimitiveType, UINT VertexCount + ...)
    ---                             ---
    D3DDevice_DrawVertices          (UINT StartVertex)
    D3DDevice_DrawVerticesUP        (void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
    D3DDevice_DrawIndexedVertices   (WORD *pIndexData)
    D3DDevice_DrawIndexedVerticesUP (WORD *pIndexData, void *pVertexStreamZeroData, UINT VertexStreamZeroStride)

(In the rest of this text, the "D3DDevice_" prefix is sometimes left out for terseness.)

Xbox also supports immediate drawing, using one D3DDevice_BeginPush call, a D3DDevice_SetVertexData* call per vertex and one D3DDevice_EndPush API call. Similar to the other Xbox D3D APIs, these APIs "push" commands and data towards the Xbox GPU (called NV2A) to perform drawing.

( As an optimization, most of these "push buffer commands" generated by Xbox D3D APIs can be recorded and replayed back to the NV2A. Even though playing back these pre-recorded push buffers may require "fixups", it's still faster than repeating the original D3D APIs.)

Most drawing-related commands on NV2A are part of the so-called Kelvin Primitive (or Object, as there's many objects on NV2A - Kelvin has code NV097).

Kelvin Commands that are used for drawing (with their data arguments) :

  • NV097_SET_BEGIN_END : Initializes the PrimitiveType to draw, and triggers the draw once all data was send
  • NV097_SET_VERTEX[_DATA_][2|3|4][F|F_M|S|S_M|UB] : Updates current attribute data (by the various SetVertexData* APIs)
  • NV097_SET_VERTEX_DATA_ARRAY_FORMAT : Sets the format of attribute data stored in vertex buffer memory
  • NV097_SET_VERTEX_DATA_ARRAY_OFFSET : Sets the starting memory address (and stride) for each attribute in the vertex buffer
  • NV097_DRAW_ARRAYS : Supplies count and starting vertex index in the active vertex buffers
  • NV097_INLINE_ARRAY : Supplies attribute data of the vertices to be drawn
  • NV097_ARRAY_ELEMENT[16|32]

D3DDevice_DrawVertices

  • NV097_SET_VERTEX_DATA_ARRAY_FORMAT (via SetStateVB)
  • NV097_SET_VERTEX_DATA_ARRAY_OFFSET (via SetStateVB)
  • NV097_SET_BEGIN_END
  • NV097_DRAW_ARRAYS

D3DDevice_DrawVerticesUP

  • NV097_SET_VERTEX_DATA_ARRAY_FORMAT (via SetStateUP)
  • NV097_SET_BEGIN_END
  • NV097_INLINE_ARRAY

D3DDevice_DrawIndexedVertices

  • NV097_SET_VERTEX_DATA_ARRAY_FORMAT (via SetStateVB)
  • NV097_SET_VERTEX_DATA_ARRAY_OFFSET (via SetStateVB)
  • NV097_SET_BEGIN_END
  • NV097_ARRAY_ELEMENT16

D3DDevice_DrawIndexedVerticesUP

  • NV097_SET_VERTEX_DATA_ARRAY_FORMAT (via SetStateUP)
  • NV097_SET_BEGIN_END
  • NV097_INLINE_ARRAY

Xbox also supports two derived Draw APIs :

  1. D3DDevice_DrawTriPatch
  2. D3DDevice_DrawRectPatch Which get converted into push buffer commands, comparable to the Draw*Vertices* APIs.

On Xbox, the D3DDevice_SetIndices API is also available, mostly as compatibility with Windows Direct3D 8; It writes the supplied index data to a global called D3D__IndexData, which is used by macro's that mimick Windows' DrawPrimitive APIs. (These macro's forward to the vertex-based Xbox Draw APIs.) The second argument to D3DDevice_SetIndices, IndexBase is stored internally and only used for D3DDevice_DrawIndexedVertices

TODO : Describe how SetStreamSource and SetVertexShaderInput[Direct] tie into the above