Because both the CPU and GPU have their own memory, it is necessary to distinguish which memory Smalltalk is to use.

In Smalltalk MT, if you were to say:

    vertices := #[
        0.0 0.5 0.5
        0.5 -0.5 0.5
        -0.5 -0.5 0.5
    ].

then Smalltalk MT will create for you an array of 3 vertex points in CPU memory.

If you want to create 3 vertex points on the GPU then you have to move these points from CPU memory to the GPU. This is a 3 step process.

Create a Buffer Description

When creating a vertex buffer, a buffer description (see D3D10_BUFFER_DESC) is used to define how data is organized within the buffer, how the Graphics pipeline can access the buffer, and how the buffer will be used.

The following example demonstrates how to create a buffer description for the single triangle above with vertices that contains position only.

bd := DX::D3D10_BUFFER_DESC new.
bd ByteWidth: vertices sizeInBytes. "Size of the buffer in bytes"
bd Usage: D3D10_USAGE_IMMUTABLE.
bd BindFlags: D3D10_BIND_VERTEX_BUFFER.
bd CPUAccessFlags: 0. "No CPU access is required"
bd MiscFlags: 0.

Create the Initialization Data for the Buffer

A buffer is just a collection of elements and is laid out as a 1D array. As a result, the system memory pitch and system memory slice pitch are both the same; the size of the vertex data declaration. An application can provide initialization data when a buffer is created using a subresource description, which contains a pointer to the actual resource data and contains information about the size and layout of that data.

The following shows the how the subresource is created:

initData := DX::D3D10_SUBRESOURCE_DATA new.
initData pSysMem: vertices basicAddress.

Create the Buffer

Using the buffer description and the initialization data (which is optional) call ID3D10Device::CreateBuffer to create a vertex buffer. The following code snippet demonstrates how to create a vertex buffer from an array of vertex data declared by the application. In this case, the buffer is created and initialized with the data from the subresource created above.

ppBuffer := LONG new.
(hr := m_pd3dDevice CreateBuffer: bd basicAddress pInitialData: initData basicAddress ppBuffer: ppBuffer basicAddress) == S_OK ifFalse: [
    Processor outputDebugLine: 'CreateBuffer FAILED'.
    ^nil
].
m_pVertexBuffer := DX::ID3D10Buffer fromAddress: ppBuffer.

Comparison

So why is this so complicated by comparison with the CPU memory option?

The reason is because the GPU is not a general purpose processor. The GPU has to know what the data will be used for and where to place it. So the first step was to create a buffer description for a certain purpose. In this case, this buffer is to be used for vertices. The vertex data only need to be read by the GPU so this determines where is can be placed.

The second step is optional and fills the buffer with data.

In the last step, the buffer was created and initialized with the subresource data.

Alternatives

Alternatively, one can create an empty buffer for the GPU and populate it later using CopyResource (to copy an entire resource) or CopySubresourceRegion/UpdateSubresource (to copy a portion of a resource). For more information see Resources (Direct3D 10).