Opdrachtenlijsten en bundels maken en opnemen
In dit onderwerp worden de opnameopdrachtlijsten en bundels in Direct3D 12-apps beschreven. Met opdrachtenlijsten en bundels kunnen apps oproepen vastleggen voor het tekenen of wijzigen van statussen, voor latere uitvoering op de GPU (grafische verwerkingseenheid).
Naast opdrachtlijsten maakt de API gebruik van functionaliteit die aanwezig is in GPU-hardware door een tweede niveau van opdrachtlijsten toe te voegen, die worden aangeduid als bundels. Het doel van bundels is dat apps een klein aantal API-opdrachten kunnen groeperen voor latere uitvoering. Tijdens het maken van bundels zal het stuurprogramma zoveel mogelijk voorverwerking uitvoeren om deze goedkoop te maken om later uit te voeren. Bundels zijn ontworpen om elk gewenst aantal keren te worden gebruikt en opnieuw gebruikt. Opdrachtlijsten worden daarentegen meestal slechts één keer uitgevoerd. Een opdrachtlijst kan echter meerdere keren worden uitgevoerd (zolang de toepassing ervoor zorgt dat de vorige uitvoeringen zijn voltooid voordat nieuwe uitvoeringen worden verzonden).
De opbouw van API-aanroepen in bundels en API-aanroepen en bundels in opdrachtlijsten, en opdrachtlijsten in één frame, wordt echter weergegeven in het volgende diagram, waarbij wordt aangegeven dat Bundel 1 opnieuw wordt gebruikt in Opdrachtlijst 1 en Opdrachtlijst 2, en dat de API-methodenamen in het diagram net als voorbeelden zijn, veel verschillende API-aanroepen kunnen worden gebruikt.
Er zijn verschillende beperkingen voor het maken en uitvoeren van bundels en lijsten met directe opdrachten. Deze verschillen worden in dit onderwerp vermeld.
Opdrachtlijsten maken
Lijsten met directe opdrachten en bundels worden gemaakt door ID3D12Device::CreateCommandList of ID3D12Device4::CreateCommandList1aan te roepen.
Gebruik ID3D12Device4::CreateCommandList1 om een gesloten opdrachtlijst te maken in plaats van een nieuwe lijst te maken en deze onmiddellijk te sluiten. Dit voorkomt de inefficiëntie van het maken van een lijst met een allocator en PSO zonder deze te gebruiken.
ID3D12Device::CreateCommandList gebruikt de volgende parameters als invoer:
D3D12_COMMAND_LIST_TYPE
De opsomming D3D12_COMMAND_LIST_TYPE geeft het type opdrachtlijst aan dat wordt gemaakt. Dit kan een directe opdrachtlijst, een bundel, een lijst met rekenopdrachten of een kopieeropdrachtlijst zijn.
ID3D12CommandAllocator
Met een opdrachttoewijzing kan de app het geheugen beheren dat is toegewezen voor opdrachtlijsten. De opdrachttoewijzing wordt gemaakt door CreateCommandAllocatoraan te roepen. Wanneer u een opdrachtlijst maakt, moet het opdrachtlijsttype van de allocator, opgegeven door D3D12_COMMAND_LIST_TYPE, overeenkomen met het type opdrachtlijst dat wordt gemaakt. Een bepaalde allocator kan worden gekoppeld aan niet meer dan één die momenteel een-opdrachtlijst opneemt, hoewel één commandtoewijzer kan worden gebruikt om een willekeurig aantal GraphicsCommandList-objecten te maken.
Een app roept ID3D12CommandAllocator::Resetom het geheugen vrij te maken dat is toegewezen door een opdrachttoewijzing. Hierdoor kan de allocator opnieuw worden gebruikt voor nieuwe opdrachten, maar wordt de onderliggende grootte niet verkleind. Maar voordat u dit doet, moet de app ervoor zorgen dat de GPU geen opdrachtlijsten meer uitvoert die zijn gekoppeld aan de allocator; anders mislukt de aanroep. Houd er ook rekening mee dat deze API niet threadveilig is en daarom niet tegelijkertijd door meerdere threads op dezelfde allocator kan worden aangeroepen.
ID3D12PipelineState
De eerste pijplijnstatus voor de opdrachtlijst. In Microsoft Direct3D 12 wordt de meeste grafische pijplijnstatus ingesteld in een opdrachtlijst met behulp van het ID3D12PipelineState-object. Een app maakt een groot aantal van deze, meestal tijdens de initialisatie van de app, en vervolgens wordt de status bijgewerkt door het huidige afhankelijke statusobject te wijzigen met behulp van ID3D12GraphicsCommandList::SetPipelineState. Zie Grafische pijplijnstatus beheren in Direct3D 12voor meer informatie over pijplijnstatusobjecten.
Houd er rekening mee dat bundels niet de pijplijnstatus overnemen die is ingesteld door eerdere aanroepen in lijsten met directe opdrachten die hun ouders zijn.
Als deze parameter NULL is, wordt een standaardstatus gebruikt.
Opdrachtlijsten opnemen
Onmiddellijk nadat de opdrachtlijsten zijn gemaakt, zijn ze in de opnamestaat. U kunt ook een bestaande opdrachtlijst opnieuw gebruiken door ID3D12GraphicsCommandList::Resetaan te roepen, waardoor ook de opdrachtlijst in de opnamestatus blijft. In tegenstelling tot ID3D12CommandAllocator::Resetkunt u opnieuw instellen aanroepen terwijl de opdrachtlijst nog steeds wordt uitgevoerd. Een typisch patroon is het verzenden van een opdrachtlijst en deze vervolgens onmiddellijk opnieuw instellen om het toegewezen geheugen voor een andere opdrachtlijst opnieuw te gebruiken. Houd er rekening mee dat slechts één opdrachtlijst die is gekoppeld aan elke opdracht-allocator tegelijk een opnamestatus heeft.
Zodra een opdrachtlijst de opnamestatus heeft, roept u gewoon methoden aan van de ID3D12GraphicsCommandList interface om opdrachten toe te voegen aan de lijst. Veel van deze methoden maken algemene Direct3D-functionaliteit mogelijk die bekend is met Microsoft Direct3D 11-ontwikkelaars; andere API's zijn nieuw voor Direct3D 12.
Nadat u opdrachten aan de opdrachtlijst hebt toegevoegd, schakelt u de opdrachtlijst uit de opnamestatus door sluiten aan te roepen.
Opdrachttoewijzers kunnen groeien, maar niet krimpen - pooling en hergebruik van toewijzers zou moeten worden overwogen om de efficiëntie van uw app te maximaliseren. U kunt meerdere lijsten opnemen in dezelfde allocator voordat deze opnieuw wordt ingesteld, mits slechts één lijst tegelijk wordt opgenomen in een bepaalde allocator. U kunt zich elke lijst voorstellen als eigenaar van een deel van de allocator, wat aangeeft welke lijsten moeten worden uitgevoerd door ID3D12CommandQueue::ExecuteCommandLists.
Een eenvoudige poolstrategie voor toewijzers zou zich moeten richten op ongeveer numCommandLists * MaxFrameLatency
. Als u bijvoorbeeld 6 lijsten opneemt en maximaal 3 latente frames toestaat, kunt u redelijkerwijs 18-20 toewijzingen verwachten. Een geavanceerdere poolstrategie, die allocators voor meerdere lijsten op dezelfde thread hergebruikt, kan zich richten op numRecordingThreads * MaxFrameLatency
allocators. Als in het vorige voorbeeld twee lijsten zijn vastgelegd op thread A, 2 op thread B, 1 op thread C en 1 op thread D, kunt u realistisch streven naar 12-14 allocators.
Gebruik een barrière om te bepalen wanneer een bepaalde allocator opnieuw gebruikt kan worden.
Omdat opdrachtlijsten onmiddellijk opnieuw kunnen worden ingesteld na uitvoering, kunnen ze triviaal worden gegroepeerd, waarna ze na elke aanroep naar ID3D12CommandQueue::ExecuteCommandListsworden toegevoegd aan de pool.
Voorbeeld
De volgende codefragmenten illustreren het maken en opnemen van een opdrachtlijst. Houd er rekening mee dat dit voorbeeld de volgende Direct3D 12-functies bevat:
- Pijplijnstatusobjecten: deze worden gebruikt om de meeste statusparameters van de render-pijplijn in te stellen vanuit een opdrachtlijst. Zie Grafische pijplijnstatus beheren in Direct3D 12voor meer informatie.
- Descriptor-heap: apps gebruiken descriptor-heaps om pijplijnbinding met geheugenbronnen te beheren.
- Resource-barrière: dit wordt gebruikt om de overgang van resources van de ene toestand naar de andere te beheren, zoals van een render target view naar een shader resource view. Zie Resourcebarrières gebruiken om resourcestatussen te synchroniserenvoor meer informatie.
Bijvoorbeeld
void D3D12HelloTriangle::LoadAssets()
{
// Create an empty root signature.
{
CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc;
rootSignatureDesc.Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
ComPtr<ID3DBlob> signature;
ComPtr<ID3DBlob> error;
ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error));
ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));
}
// Create the pipeline state, which includes compiling and loading shaders.
{
ComPtr<ID3DBlob> vertexShader;
ComPtr<ID3DBlob> pixelShader;
#if defined(_DEBUG)
// Enable better shader debugging with the graphics debugging tools.
UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#else
UINT compileFlags = 0;
#endif
ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr));
ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr));
// Define the vertex input layout.
D3D12_INPUT_ELEMENT_DESC inputElementDescs[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
};
// Describe and create the graphics pipeline state object (PSO).
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
psoDesc.pRootSignature = m_rootSignature.Get();
psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()), vertexShader->GetBufferSize() };
psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()), pixelShader->GetBufferSize() };
psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
psoDesc.DepthStencilState.DepthEnable = FALSE;
psoDesc.DepthStencilState.StencilEnable = FALSE;
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
psoDesc.SampleDesc.Count = 1;
ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState)));
}
// Create the command list.
ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList)));
// Command lists are created in the recording state, but there is nothing
// to record yet. The main loop expects it to be closed, so close it now.
ThrowIfFailed(m_commandList->Close());
// Create the vertex buffer.
{
// Define the geometry for a triangle.
Vertex triangleVertices[] =
{
{ { 0.0f, 0.25f * m_aspectRatio, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
{ { 0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
{ { -0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }
};
const UINT vertexBufferSize = sizeof(triangleVertices);
// Note: using upload heaps to transfer static data like vert buffers is not
// recommended. Every time the GPU needs it, the upload heap will be marshalled
// over. Please read up on Default Heap usage. An upload heap is used here for
// code simplicity and because there are very few verts to actually transfer.
ThrowIfFailed(m_device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
D3D12_HEAP_FLAG_NONE,
&CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&m_vertexBuffer)));
// Copy the triangle data to the vertex buffer.
UINT8* pVertexDataBegin;
CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU.
ThrowIfFailed(m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin)));
memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices));
m_vertexBuffer->Unmap(0, nullptr);
// Initialize the vertex buffer view.
m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress();
m_vertexBufferView.StrideInBytes = sizeof(Vertex);
m_vertexBufferView.SizeInBytes = vertexBufferSize;
}
// Create synchronization objects and wait until assets have been uploaded to the GPU.
{
ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)));
m_fenceValue = 1;
// Create an event handle to use for frame synchronization.
m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (m_fenceEvent == nullptr)
{
ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
}
// Wait for the command list to execute; we are reusing the same command
// list in our main loop but for now, we just want to wait for setup to
// complete before continuing.
WaitForPreviousFrame();
}
}
Nadat een opdrachtlijst is gemaakt en vastgelegd, kan deze worden uitgevoerd met behulp van een opdrachtwachtrij. Zie Opdrachtenlijsten uitvoeren en synchroniserenvoor meer informatie.
Referentie tellen
De meeste D3D12-API's blijven referentietellingen gebruiken volgens com-conventies. Een belangrijke uitzondering hierop is de D3D12 graphics command list API's. Alle API's op ID3D12GraphicsCommandList bevatten geen verwijzingen naar de objecten die zijn doorgegeven aan deze API's. Dit betekent dat toepassingen verantwoordelijk zijn om ervoor te zorgen dat er nooit een opdrachtlijst wordt verzonden voor uitvoering die verwijst naar een vernietigde resource.
Fouten in opdrachtlijst
De meeste API's op ID3D12GraphicsCommandList retourneren geen fouten. Fouten die zijn opgetreden tijdens het maken van de opdrachtlijst worden uitgesteld totdat ID3D12GraphicsCommandList::Close. De enige uitzondering is DXGI_ERROR_DEVICE_REMOVED, dat nog verder wordt uitgesteld. Houd er rekening mee dat dit verschilt van D3D11, waarbij veel parametervalidatiefouten op de achtergrond worden verwijderd en nooit worden geretourneerd naar de aanroeper.
Toepassingen kunnen verwachten DXGI_DEVICE_REMOVED-fouten te zien in de volgende API-aanroepen:
- Elke methode voor het maken van bronnen
- ID3D12Resource::Map
- IDXGISwapChain1::Present1
- GetDeviceRemovedReason
API-beperkingen voor opdrachtlijst
Sommige opdrachtlijst-API's kunnen alleen worden aangeroepen op bepaalde typen opdrachtlijsten. In de onderstaande tabel ziet u welke API's van de opdrachtlijst geldig zijn om elk type opdrachtlijst aan te roepen. Er wordt ook weergegeven welke API's geldig zijn om aan te roepen in een D3D12 render-pas.
API-naam | Grafiek | Berekenen | Kopiëren | Bundel | In Render Pass |
---|---|---|---|---|---|
AtomicCopyBufferUINT | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
AtomicCopyBufferUINT64 | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
BeginQuery | ✓ Geldig | ✓ Geldig | |||
BeginRenderPass | ✓ Geldig | ||||
BouwRaytracingVersnellingsStructuur | ✓ Geldig | ✓ Geldig | |||
ClearDepthStencilView | ✓ Geldig | ||||
ClearRenderTargetView | ✓ Geldig | ||||
ClearState | ✓ Geldig | ✓ Geldig | |||
ClearUnorderedAccessViewFloat | ✓ Geldig | ✓ Geldig | |||
ClearUnorderedAccessViewUint | ✓ Geldig | ✓ Geldig | |||
CopyBufferRegion | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
KopieerRaytracingVersnellingsstructuur | ✓ Geldig | ✓ Geldig | |||
CopyResource | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
CopyTextureRegion | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
CopyTiles | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
DiscardResource | ✓ Geldig | ✓ Geldig | |||
Verzenden | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
DispatchRays | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
DrawIndexedInstanced | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
DrawInstanced | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
EmitRaytracingAccelerationStructurePostbuildInfo | ✓ Geldig | ✓ Geldig | |||
EndQuery | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
EndRenderPass | ✓ Geldig | ✓ Geldig | |||
ExecuteBundle | ✓ Geldig | ✓ Geldig | |||
ExecuteIndirect | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
ExecuteMetaCommand | ✓ Geldig | ✓ Geldig | |||
IASetIndexBuffer | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
IASetPrimitiveTopology | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
IASetVertexBuffers | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
InitializeMetaCommand | ✓ Geldig | ✓ Geldig | |||
OMSetBlendFactor | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
OMSetDepthBounds | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
OMSetRenderTargets | ✓ Geldig | ||||
OMSetStencilRef | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
ResolveQueryData | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
ResolveSubresource | ✓ Geldig | ||||
ResolveSubresourceRegio | ✓ Geldig | ||||
ResourceBarrier (Middelbarrière) | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
RSSetScissorRects | ✓ Geldig | ✓ Geldig | |||
RSSetShadingRate | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
RSSetShadingRateImage | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
RSSetViewports | ✓ Geldig | ✓ Geldig | |||
SetComputeRoot32BitConstant | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
SetComputeRoot32BitConstants | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
SetComputeRootConstantBufferView | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
SetComputeRootDescriptorTable | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
SetComputeRootShaderResourceView | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
SetComputeRootSignature | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
SetComputeRootOngeordendeToegangsWeergave | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
SetDescriptorHeaps | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
SetGraphicsRoot32BitConstant | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
SetGraphicsRoot32BitConstants | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
SetGraphicsRootConstantBufferView | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
SetGraphicsRootDescriptorTable | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
SetGraphicsRootShaderResourceView | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
SetGraphicsRootSignature (GrafischeHandofftekeningInstellen) | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
SetGraphicsRootUnorderedAccessView | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
StelPijplijnStatusIn | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | |
SetPipelineState1 | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
SetPredication | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
SetProtectedResourceSession | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
SetSamplePositions | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
SetViewInstanceMask | ✓ Geldig | ✓ Geldig | ✓ Geldig | ||
SOSetTargets | ✓ Geldig | ✓ Geldig | |||
WriteBufferImmediate | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig | ✓ Geldig |
Bundelbeperkingen
Met beperkingen kunnen Direct3D 12-stuurprogramma's het meeste werk uitvoeren dat is gekoppeld aan bundels tijdens recordtijd, waardoor de ExecuteBundle--API kan worden uitgevoerd met een lage overhead. Alle pijplijnstatusobjecten waarnaar wordt verwezen door een bundel, moeten dezelfde renderdoelindelingen, dieptebufferindeling en voorbeeldbeschrijvingen hebben.
De volgende API-aanroepen van de opdrachtlijst zijn niet toegestaan voor opdrachtlijsten die zijn gemaakt met het type: D3D12_COMMAND_LIST_TYPE_BUNDLE:
- Elke willekeurige Clear-methode
- Elke kopieermethode
- DiscardResource
- ExecuteBundle
- ResourceBarrier
- ResolveSubresource
- SetPredication
- BeginQuery
- EndQuery
- SOSetTargets
- OMSetRenderTargets -
- RSSetViewports
- RSSetScissorRects
SetDescriptorHeaps kan worden aangeroepen op een bundel, maar de bundel descriptor-heaps moeten overeenkomen met de descriptor heap van de aanroepende opdrachtlijst.
Als een van deze API's wordt aangeroepen op een bundel, zal de runtime de aanroep afbreken. De foutopsporingslaag geeft een fout wanneer dit optreedt.