Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Menunjukkan cara menggunakan satu penyangga untuk memasukkan data penyangga konstan dan data penyangga vertex ke GPU, serta cara melakukan alokasi parsial dan menempatkan data dengan benar dalam penyangga. Penggunaan buffer tunggal meningkatkan fleksibilitas penggunaan memori, dan menyediakan aplikasi dengan kontrol yang lebih ketat atas penggunaan memori. Juga menunjukkan perbedaan antara model Direct3D 11 dan Direct3D 12 untuk mengunggah berbagai jenis sumber daya.
Mengunggah berbagai jenis sumber daya
Di Direct3D 12, Anda membuat satu buffer untuk mengakomodasi berbagai jenis data sumber daya untuk diunggah, dan Anda menyalin data sumber daya ke buffer yang sama dengan cara yang sama untuk data sumber daya yang berbeda. Tampilan individual kemudian dibuat untuk mengikat data sumber daya tersebut ke alur grafis dalam model pengikatan sumber daya Direct3D 12.
Di Direct3D 11, Anda membuat buffer terpisah untuk berbagai jenis data sumber daya (perhatikan berbagai yang BindFlags digunakan dalam kode sampel Direct3D 11 di bawah), secara eksplisit mengikat setiap buffer sumber daya ke alur grafis, dan memperbarui data sumber daya dengan metode yang berbeda berdasarkan jenis sumber daya yang berbeda.
Dalam Direct3D 12 dan Direct3D 11, Anda harus menggunakan sumber daya unggah hanya di mana CPU akan menulis data sekali, dan GPU akan membacanya sekali.
Dalam beberapa kasus,
- GPU akan membaca data beberapa kali, atau
- GPU tidak akan membaca data secara linier, atau
- Pengolahan sudah secara signifikan dibatasi oleh GPU.
Dalam kasus tersebut, opsi yang lebih baik mungkin menggunakan ID3D12GraphicsCommandList::CopyTextureRegion atau ID3D12GraphicsCommandList::CopyBufferRegion untuk menyalin data buffer unggahan ke sumber daya default.
Sumber daya default dapat berada di memori video fisik pada GPU diskrit.
Contoh Kode: Direct3D 11
// Direct3D 11: Separate buffers for each resource type.
void main()
{
// ...
// Create a constant buffer.
float constantBufferData[] = ...;
D3D11_BUFFER_DESC constantBufferDesc = {0};
constantBufferDesc.ByteWidth = sizeof(constantBufferData);
constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
ComPtr<ID3D11Buffer> constantBuffer;
d3dDevice->CreateBuffer(
&constantBufferDesc,
NULL,
&constantBuffer
);
// Create a vertex buffer.
float vertexBufferData[] = ...;
D3D11_BUFFER_DESC vertexBufferDesc = { 0 };
vertexBufferDesc.ByteWidth = sizeof(vertexBufferData);
vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
ComPtr<ID3D11Buffer> vertexBuffer;
d3dDevice->CreateBuffer(
&vertexBufferDesc,
NULL,
&vertexBuffer
);
// ...
}
void DrawFrame()
{
// ...
// Bind buffers to the graphics pipeline.
d3dDeviceContext->VSSetConstantBuffers(0, 1, constantBuffer.Get());
d3dDeviceContext->IASetVertexBuffers(0, 1, vertexBuffer.Get(), ...);
// Update the constant buffer.
D3D11_MAPPED_SUBRESOURCE mappedResource;
d3dDeviceContext->Map(
constantBuffer.Get(),
0,
D3D11_MAP_WRITE_DISCARD,
0,
&mappedResource
);
memcpy(mappedResource.pData, constantBufferData,
sizeof(contatnBufferData));
d3dDeviceContext->Unmap(constantBuffer.Get(), 0);
// Update the vertex buffer.
d3dDeviceContext->UpdateSubresource(
vertexBuffer.Get(),
0,
NULL,
vertexBufferData,
sizeof(vertexBufferData),
0
);
// ...
}
Contoh Kode: Direct3D 12
// Direct3D 12: One buffer to accommodate different types of resources
ComPtr<ID3D12Resource> m_spUploadBuffer;
UINT8* m_pDataBegin = nullptr; // starting position of upload buffer
UINT8* m_pDataCur = nullptr; // current position of upload buffer
UINT8* m_pDataEnd = nullptr; // ending position of upload buffer
void main()
{
//
// Initialize an upload buffer
//
InitializeUploadBuffer(64 * 1024);
// ...
}
void DrawFrame()
{
// ...
// Set vertices data to the upload buffer.
float vertices[] = ...;
UINT verticesOffset = 0;
ThrowIfFailed(
SetDataToUploadBuffer(
vertices, sizeof(float), sizeof(vertices) / sizeof(float),
sizeof(float),
verticesOffset
));
// Set constant data to the upload buffer.
float constants[] = ...;
UINT constantsOffset = 0;
ThrowIfFailed(
SetDataToUploadBuffer(
constants, sizeof(float), sizeof(constants) / sizeof(float),
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT,
constantsOffset
));
// Create vertex buffer views for the new binding model.
D3D12_VERTEX_BUFFER_VIEW vertexBufferViewDesc = {
m_spUploadBuffer->GetGPUVirtualAddress() + verticesOffset,
sizeof(vertices), // size
sizeof(float) * 4, // stride
};
commandList->IASetVertexBuffers(
0,
1,
&vertexBufferViewDesc,
));
// Create constant buffer views for the new binding model.
D3D12_CONSTANT_BUFFER_VIEW_DESC constantBufferViewDesc = {
m_spUploadBuffer->GetGPUVirtualAddress() + constantsOffset,
sizeof(constants) // size
};
d3dDevice->CreateConstantBufferView(
&constantBufferViewDesc,
...
));
// Continue command list building and execution ...
}
//
// Create an upload buffer and keep it always mapped.
//
HRESULT InitializeUploadBuffer(SIZE_T uSize)
{
HRESULT hr = d3dDevice->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_UPLOAD ),
D3D12_HEAP_FLAG_NONE,
&CD3DX12_RESOURCE_DESC::Buffer( uSize ),
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
IID_PPV_ARGS( &m_spUploadBuffer ) );
if (SUCCEEDED(hr))
{
void* pData;
//
// No CPU reads will be done from the resource.
//
CD3DX12_RANGE readRange(0, 0);
m_spUploadBuffer->Map( 0, &readRange, &pData );
m_pDataCur = m_pDataBegin = reinterpret_cast< UINT8* >( pData );
m_pDataEnd = m_pDataBegin + uSize;
}
return hr;
}
//
// Sub-allocate from the buffer, with offset aligned.
//
HRESULT SuballocateFromBuffer(SIZE_T uSize, UINT uAlign)
{
m_pDataCur = reinterpret_cast< UINT8* >(
Align(reinterpret_cast< SIZE_T >(m_pDataCur), uAlign)
);
return (m_pDataCur + uSize > m_pDataEnd) ? E_INVALIDARG : S_OK;
}
//
// Place and copy data to the upload buffer.
//
HRESULT SetDataToUploadBuffer(
const void* pData,
UINT bytesPerData,
UINT dataCount,
UINT alignment,
UINT& byteOffset
)
{
SIZE_T byteSize = bytesPerData * dataCount;
HRESULT hr = SuballocateFromBuffer(byteSize, alignment);
if (SUCCEEDED(hr))
{
byteOffset = UINT(m_pDataCur - m_pDataBegin);
memcpy(m_pDataCur, pData, byteSize);
m_pDataCur += byteSize;
}
return hr;
}
//
// Align uLocation to the next multiple of uAlign.
//
UINT Align(UINT uLocation, UINT uAlign)
{
if ( (0 == uAlign) || (uAlign & (uAlign-1)) )
{
ThrowException("non-pow2 alignment");
}
return ( (uLocation + (uAlign-1)) & ~(uAlign-1) );
}
Perhatikan penggunaan struktur pembantu CD3DX12_HEAP_PROPERTIES dan CD3DX12_RESOURCE_DESC.
Konstanta
Untuk mengatur konstanta, simpul, dan indeks dalam heap pengunggahan atau pembacaan balik, gunakan API berikut.
- ID3D12Device::CreateConstantBufferView
- ID3D12GraphicsCommandList::IASetVertexBuffers
- ID3D12GraphicsCommandList::IASetIndexBuffer
Sumber
Sumber daya adalah konsep Direct3D yang mengabstraksi penggunaan memori fisik GPU. Sumber daya memerlukan ruang alamat virtual GPU untuk mengakses memori fisik. Pembuatan sumber daya berutas bebas.
Ada tiga jenis sumber daya sehubungan dengan pembuatan dan fleksibilitas alamat virtual di Direct3D 12.
Sumber daya berkomitmen
Sumber daya yang berkomitmen adalah ide paling umum tentang sumber daya Direct3D selama generasi. Membuat sumber daya seperti itu mengalokasikan kisaran alamat virtual, tumpukan implisit yang cukup besar untuk mencakup seluruh sumber daya, dan mengaitkan kisaran alamat virtual ke memori fisik yang dienkapsulasi oleh tumpukan. Properti timbunan implisit harus diteruskan agar sesuai dengan paritas fungsional dengan versi Direct3D sebelumnya. Rujuk ke ID3D12Device::CreateCommittedResource.
Sumber daya yang dipesan
Sumber daya yang dipesan setara dengan sumber daya berpola kisi Direct3D 11. Pada pembuatannya, hanya rentang alamat virtual yang dialokasikan, dan tidak dipetakan ke tumpukan apa pun. Aplikasi akan memetakan sumber daya tersebut ke tumpukan nanti. Kemampuan sumber daya tersebut saat ini tidak berubah dari Direct3D 11, karena dapat dipetakan ke tumpukan pada granularitas petak peta 64KB dengan UpdateTileMappings. Lihat ID3D12Device::CreateReservedResource.
Sumber daya yang ditempatkan
Baru untuk Direct3D 12, Anda dapat membuat timbunan yang terpisah dari sumber daya. Setelah itu, Anda dapat menemukan beberapa sumber daya dalam satu timbunan. Anda dapat melakukannya tanpa membuat sumber daya ubin atau cadangan, memungkinkan kemampuan untuk semua jenis sumber daya dapat dibuat langsung oleh aplikasi Anda. Beberapa sumber daya mungkin tumpang tindih, dan Anda harus menggunakan ID3D12GraphicsCommandList::ResourceBarrier untuk menggunakan kembali memori fisik dengan benar. Rujuk ke ID3D12Device::CreatePlacedResource.
Representasi ukuran sumber daya
Anda harus menggunakan refleksi ukuran sumber daya untuk memahami seberapa banyak ruang yang diperlukan oleh tekstur dengan tata letak yang tidak diketahui dalam tumpukan. Buffer juga didukung, tetapi terutama untuk kemudahan.
Anda harus menyadari perbedaan penyelarasan utama, untuk membantu mengemas sumber daya dengan lebih padat.
Misalnya, array elemen tunggal dengan buffer satu byte mengembalikan Ukuran 64KB, dan Perataan 64KB, karena buffer hanya dapat disejajarkan sebesar 64KB.
Selain itu, array tiga elemen dengan dua tekstur selaras 64KB texel tunggal dan tekstur selaras 4MB texel tunggal melaporkan ukuran yang berbeda berdasarkan urutan array. Jika tekstur sejajar 4MB berada di tengah, maka Ukuran yang dihasilkan adalah 12MB. Jika tidak, Ukuran yang dihasilkan adalah 8MB. Penyelarasan yang dikembalikan akan selalu 4MB, superset dari semua penyelarasan dalam array sumber.
Referensikan API berikut.
Penyelarasan buffer
Pembatasan penyelarasan buffer tidak berubah dari Direct3D 11, terutama:
- 4 MB untuk tekstur multi-sampel.
- 64 KB untuk tekstur dan buffer sampel tunggal.