Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Laat zien hoe u één buffer gebruikt om zowel constante buffergegevens als hoekpuntbuffergegevens te uploaden naar de GPU en hoe u gegevens correct in buffers kunt toewijzen en plaatsen. Het gebruik van één buffer verhoogt de flexibiliteit van het geheugengebruik en biedt toepassingen een strakkere controle over het geheugengebruik. Toont ook de verschillen tussen de Direct3D 11- en Direct3D 12-modellen voor het uploaden van verschillende typen resources.
Verschillende typen resources uploaden
In Direct3D 12 maakt u één buffer voor verschillende typen resourcegegevens voor het uploaden en kopieert u resourcegegevens op een vergelijkbare manier naar dezelfde buffer voor verschillende resourcegegevens. Afzonderlijke weergaven worden vervolgens gemaakt om deze resourcegegevens te binden aan de grafische pijplijn in het direct3D 12-resourcebindingsmodel.
In Direct3D 11 maakt u afzonderlijke buffers voor verschillende typen resourcegegevens (let op de verschillende BindFlags die in de onderstaande voorbeeldcode van Direct3D 11 worden gebruikt), verbindt u elke resourcebuffer expliciet aan de grafische pijplijn en werkt u de resourcegegevens bij met verschillende methoden op basis van verschillende resourcetypen.
In zowel Direct3D 12 als Direct3D 11 moet u alleen uploadbronnen gebruiken waarbij de CPU de gegevens eenmaal schrijft en de GPU deze eenmaal leest.
In sommige gevallen,
- de GPU leest de gegevens meerdere keren, of
- de GPU leest de gegevens niet lineair of
- De rendering is al aanzienlijk GPU-beperkt.
In die gevallen is het mogelijk beter om ID3D12GraphicsCommandList::CopyTextureRegion of ID3D12GraphicsCommandList::CopyBufferRegion te gebruiken om de uploadbuffergegevens te kopiëren naar een standaardresource.
Een standaardresource kan zich in het fysieke videogeheugen bevinden op discrete GPU's.
Codevoorbeeld: 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
);
// ...
}
Codevoorbeeld: 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) );
}
Let op het gebruik van de helperstructuren CD3DX12_HEAP_PROPERTIES en CD3DX12_RESOURCE_DESC.
Constanten
Gebruik de volgende API's om constanten, hoekpunten en indexen in te stellen binnen een upload- of readback-heap.
- ID3D12Device::CreateConstantBufferView
- ID3D12GraphicsCommandList::IASetVertexBuffers
- ID3D12GraphicsCommandList::IASetIndexBuffer
Hulpbronnen
Resources zijn het Direct3D-concept waarmee het gebruik van fysiek GPU-geheugen wordt geabstraheerd. Resources vereisen virtuele GPU-adresruimte voor toegang tot fysiek geheugen. Het maken van resources is vrij gedraad.
Er zijn drie soorten resources met betrekking tot het maken van virtuele adressen en flexibiliteit in Direct3D 12.
Toegewezen middelen
Vastgelegde resources zijn het meest voorkomende concept van Direct3D-resources door de generaties heen. Het maken van een dergelijke resource wijst een virtueel adresbereik toe, creëert een impliciete heap die groot genoeg is om de gehele resource te omvatten, en wijst het virtuele adresbereik toe aan het fysieke geheugen dat wordt ingekapseld door de heap. De impliciete heap-eigenschappen moeten worden doorgegeven om functionele pariteit te vinden met eerdere Direct3D-versies. Raadpleeg ID3D12Device::CreateCommittedResource.
Gereserveerde resources
Gereserveerde resources zijn gelijk aan Direct3D 11 tiled resources. Bij het aanmaken wordt alleen een virtueel adresbereik toegekend en niet aan een heap gekoppeld. De toepassing wijst dergelijke resources later toe aan heaps. De mogelijkheden van dergelijke resources zijn momenteel dezelfde als bij Direct3D 11, omdat ze kunnen worden toegewezen aan een heap op een niveau van 64 kB-tegels met UpdateTileMappings. Raadpleeg ID3D12Device::CreateReservedResource.
Geplaatste middelen
Nieuw voor Direct3D 12 kunt u heaps maken, gescheiden van resources. Daarna kunt u meerdere resources binnen één heap vinden. U kunt dit doen zonder tegels of gereserveerde resources te maken, waardoor de mogelijkheden voor alle resourcetypen door uw applicatie direct kunnen worden aangemaakt. Meerdere resources kunnen elkaar overlappen en u moet de ID3D12GraphicsCommandList::ResourceBarrier gebruiken om fysiek geheugen correct opnieuw te gebruiken. Raadpleeg ID3D12Device::CreatePlacedResource.
Weerspiegeling van hulpbrongrootte
U moet weerspiegeling van de resourcegrootte gebruiken om te begrijpen hoeveel ruimtetextuur met onbekende patroonindelingen nodig zijn in heaps. Buffers worden ook ondersteund, maar vooral voor het gemak.
U moet rekening houden met grote uitlijningsverschillen om resources dichter bij elkaar te brengen.
Een array met één element met een eenbyte-buffer retourneert bijvoorbeeld een Grootte van 64 kB en een Uitlijning van 64 kB, omdat buffers alleen kunnen worden uitgelijnd op 64 kB.
Ook rapporteert een array met drie elementen, met twee single-texel 64 kB uitgelijnde texturen en een single-texel 4 MB uitgelijnde textuur, verschillende groottes afhankelijk van de volgorde van de array. Als de 4MB uitgelijnde texturen zich in het midden bevinden, is de resulterende Grootte 12 MB. Anders is de resulterende grootte 8 MB. De alignment die wordt geretourneerd, is altijd 4 MB, als superset van alle alignments in de resourcematrix.
Verwijs naar de volgende API's.
Bufferuitlijning
Beperkingen voor bufferuitlijning zijn niet gewijzigd van Direct3D 11, met name:
- 4 MB voor multi-sample-texturen.
- 64 kB voor enkelvoudige texturen en buffers.