Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Para criar e configurar uma pilha de descritores, deve selecionar um tipo de pilha de descritores, determinar quantos descritores ela contém e definir sinalizadores que indiquem se é visível para o CPU e/ou visível para o sombreador.
- Tipos de descritor de heap
- Propriedades do heap de descritores
- Manipuladores de Descritores
- Métodos do Heap de Descritores
- Invólucro de pilha de descritor mínimo
- Tópicos relacionados
Tipos de descritor de heap
O tipo de pilha é determinado por um membro do D3D12_DESCRIPTOR_HEAP_TYPE enum:
typedef enum D3D12_DESCRIPTOR_HEAP_TYPE
{
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, // Constant buffer/Shader resource/Unordered access views
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, // Samplers
D3D12_DESCRIPTOR_HEAP_TYPE_RTV, // Render target view
D3D12_DESCRIPTOR_HEAP_TYPE_DSV, // Depth stencil view
D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES // Simply the number of descriptor heap types
} D3D12_DESCRIPTOR_HEAP_TYPE;
Propriedades da pilha de descritores
As propriedades de pilha são definidas na estrutura D3D12_DESCRIPTOR_HEAP_DESC, que faz referência ao D3D12_DESCRIPTOR_HEAP_TYPE e D3D12_DESCRIPTOR_HEAP_FLAGS enums.
A flag D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE pode ser definida opcionalmente numa pilha de descritores para indicar que será vinculada a uma lista de comandos para referência pelos sombreadoras. Pilhas de descritores criadas sem este sinalizador permitem que os aplicativos tenham a opção de preparar descritores na memória da CPU antes de copiá-los para um heap de descritor visível para sombreador, para conveniência. Contudo, também é perfeitamente aceitável que as aplicações criem descritores diretamente em pilhas de descritores visíveis pelo sombreador sem a necessidade de estagiar nada na CPU.
Esta bandeira aplica-se apenas a CBV, SRV, UAV e amostradores. Não se aplica a outros tipos de heap de descritores, uma vez que os sombreadores não referenciam diretamente os outros tipos.
Por exemplo, descreva e crie uma heap de descritor de amostra.
// Describe and create a sampler descriptor heap.
D3D12_DESCRIPTOR_HEAP_DESC samplerHeapDesc = {};
samplerHeapDesc.NumDescriptors = 1;
samplerHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
samplerHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
ThrowIfFailed(m_device->CreateDescriptorHeap(&samplerHeapDesc, IID_PPV_ARGS(&m_samplerHeap)));
Descreva e crie uma visão de buffer constante (CBV), uma visão de recurso de sombreador (SRV) e uma pilha de descritores de visão de acesso não ordenado (UAV).
// Describe and create a shader resource view (SRV) and unordered
// access view (UAV) descriptor heap.
D3D12_DESCRIPTOR_HEAP_DESC srvUavHeapDesc = {};
srvUavHeapDesc.NumDescriptors = DescriptorCount;
srvUavHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srvUavHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
ThrowIfFailed(m_device->CreateDescriptorHeap(&srvUavHeapDesc, IID_PPV_ARGS(&m_srvUavHeap)));
m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
m_srvUavDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
Identificadores de Referência do Descritor
As estruturas D3D12_GPU_DESCRIPTOR_HANDLE e D3D12_CPU_DESCRIPTOR_HANDLE identificam descritores específicos em uma pilha de descritores. Um identificador é um pouco como um ponteiro, mas o aplicativo não deve desreferenciar manualmente; caso contrário, o comportamento é indefinido. O uso dos identificadores deve passar pela API. Um identificador em si pode ser copiado livremente ou passado para APIs que operam em/usam descritores. Não há contagem de referências, portanto, o aplicativo deve certificar-se de que não use um identificador após o heap de descritores subjacente ter sido excluído.
As aplicações podem descobrir o tamanho de incremento dos descritores para um determinado tipo de pilha de descritores, de modo a poderem gerar identificadores para qualquer local numa pilha de descritores manualmente, partindo do identificador da base. Os aplicativos nunca devem manipular descritores de código rígido para tamanhos de incremento e devem sempre consultá-los para uma determinada instância de dispositivo; caso contrário, o comportamento é indefinido. As aplicações também não devem usar os tamanhos de incremento e identificadores para fazerem a sua própria análise ou manipulação de dados da pilha de descritores, pois os resultados disso são indefinidos. As alças não podem realmente ser usadas como ponteiros, mas sim como proxies para ponteiros para evitar desreferenciação acidental.
Observação
Há uma estrutura auxiliar, CD3DX12_GPU_DESCRIPTOR_HANDLE, definida no cabeçalho d3dx12.h, que herda a estrutura D3D12_GPU_DESCRIPTOR_HANDLE e fornece inicialização e outras operações úteis. Da mesma forma, a estrutura auxiliar CD3DX12_CPU_DESCRIPTOR_HANDLE é definida para a estrutura D3D12_CPU_DESCRIPTOR_HANDLE.
Ambas as estruturas auxiliares são usadas ao preencher listas de comandos.
// Fill the command list with all the render commands and dependent state.
void D3D12nBodyGravity::PopulateCommandList()
{
// Command list allocators can only be reset when the associated
// command lists have finished execution on the GPU; apps should use
// fences to determine GPU execution progress.
ThrowIfFailed(m_commandAllocators[m_frameIndex]->Reset());
// However, when ExecuteCommandList() is called on a particular command
// list, that command list can then be reset at any time and must be before
// re-recording.
ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_frameIndex].Get(), m_pipelineState.Get()));
// Set necessary state.
m_commandList->SetPipelineState(m_pipelineState.Get());
m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());
m_commandList->SetGraphicsRootConstantBufferView(RootParameterCB, m_constantBufferGS->GetGPUVirtualAddress() + m_frameIndex * sizeof(ConstantBufferGS));
ID3D12DescriptorHeap* ppHeaps[] = { m_srvUavHeap.Get() };
m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);
m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
m_commandList->RSSetScissorRects(1, &m_scissorRect);
// Indicate that the back buffer will be used as a render target.
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize);
m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
// Record commands.
const float clearColor[] = { 0.0f, 0.0f, 0.1f, 0.0f };
m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
// Render the particles.
float viewportHeight = static_cast<float>(static_cast<UINT>(m_viewport.Height) / m_heightInstances);
float viewportWidth = static_cast<float>(static_cast<UINT>(m_viewport.Width) / m_widthInstances);
for (UINT n = 0; n < ThreadCount; n++)
{
const UINT srvIndex = n + (m_srvIndex[n] == 0 ? SrvParticlePosVelo0 : SrvParticlePosVelo1);
D3D12_VIEWPORT viewport;
viewport.TopLeftX = (n % m_widthInstances) * viewportWidth;
viewport.TopLeftY = (n / m_widthInstances) * viewportHeight;
viewport.Width = viewportWidth;
viewport.Height = viewportHeight;
viewport.MinDepth = D3D12_MIN_DEPTH;
viewport.MaxDepth = D3D12_MAX_DEPTH;
m_commandList->RSSetViewports(1, &viewport);
CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(m_srvUavHeap->GetGPUDescriptorHandleForHeapStart(), srvIndex, m_srvUavDescriptorSize);
m_commandList->SetGraphicsRootDescriptorTable(RootParameterSRV, srvHandle);
m_commandList->DrawInstanced(ParticleCount, 1, 0, 0);
}
m_commandList->RSSetViewports(1, &m_viewport);
// Indicate that the back buffer will now be used to present.
m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[m_frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
ThrowIfFailed(m_commandList->Close());
}
Métodos de heap de descritores
Pilhas de descritores (ID3D12DescriptorHeap) herdam de ID3D12Pageable. Isso atribui aos aplicativos a responsabilidade pelo gerenciamento de heaps de descritores, assim como de heaps de recursos. Os métodos de gestão de residência só se aplicam a heaps que são visíveis pelo sombreador, uma vez que os heaps não visíveis pelo sombreador não são visíveis diretamente pela GPU.
O métodoID3D12Device::GetDescriptorHandleIncrementSizepermite que os aplicativos desloquem manualmente as alças dentro de um heap (gerando alças em qualquer posição dentro de um heap de descritores). O identificador do local de início de pilha vem de ID3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart/ID3D12DescriptorHeap::GetGPUDescriptorHandleForHeapStart. A compensação é feita adicionando o tamanho do incremento * o número de descritores a serem deslocados para o início do heap do descritor. Note que o tamanho do incremento não pode ser pensado como um tamanho de byte, porque as aplicações não devem desreferenciar alças como se fossem memória – a memória apontada tem um layout não padronizado e pode variar mesmo para um mesmo dispositivo.
GetCPUDescriptorHandleForHeapStart devolve um handle de CPU para heaps de descritor visíveis ao CPU. Ele retorna um identificador NULL (e a camada de depuração relatá um erro) se o heap do descritor não for acessível pela CPU.
GetGPUDescriptorHandleForHeapStart retorna um identificador de GPU para heaps de descritores visíveis para o sombreador. Retorna um identificador NULL (e a camada de depuração relatará um erro) se o heap do descritor não estiver visível para o shader.
Por exemplo, criar visualizações de destino de renderização para exibir texto D2D usando um dispositivo 11on12.
// Create descriptor heaps.
{
// Describe and create a render target view (RTV) descriptor heap.
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
rtvHeapDesc.NumDescriptors = FrameCount;
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
ThrowIfFailed(m_d3d12Device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap)));
m_rtvDescriptorSize = m_d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
}
// Create frame resources.
{
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());
// Create a RTV, D2D render target, and a command allocator for each frame.
for (UINT n = 0; n < FrameCount; n++)
{
ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n])));
m_d3d12Device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle);
// Create a wrapped 11On12 resource of this back buffer. Since we are
// rendering all D3D12 content first and then all D2D content, we specify
// the In resource state as RENDER_TARGET - because D3D12 will have last
// used it in this state - and the Out resource state as PRESENT. When
// ReleaseWrappedResources() is called on the 11On12 device, the resource
// will be transitioned to the PRESENT state.
D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET };
ThrowIfFailed(m_d3d11On12Device->CreateWrappedResource(
m_renderTargets[n].Get(),
&d3d11Flags,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT,
IID_PPV_ARGS(&m_wrappedBackBuffers[n])
));
// Create a render target for D2D to draw directly to this back buffer.
ComPtr<IDXGISurface> surface;
ThrowIfFailed(m_wrappedBackBuffers[n].As(&surface));
ThrowIfFailed(m_d2dDeviceContext->CreateBitmapFromDxgiSurface(
surface.Get(),
&bitmapProperties,
&m_d2dRenderTargets[n]
));
rtvHandle.Offset(1, m_rtvDescriptorSize);
ThrowIfFailed(m_d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocators[n])));
}
}
Invólucro mínimo de pilha de descritores
Os desenvolvedores de aplicativos provavelmente desejarão criar seu próprio código auxiliar para gerenciar identificadores e heaps de descritores. Um exemplo básico é mostrado abaixo. Invólucros mais sofisticados poderiam, por exemplo, controlar que tipos de descritores estão em uma pilha e armazenar os argumentos de criação do descritor.
class CDescriptorHeapWrapper
{
public:
CDescriptorHeapWrapper() { memset(this, 0, sizeof(*this)); }
HRESULT Create(
ID3D12Device* pDevice,
D3D12_DESCRIPTOR_HEAP_TYPE Type,
UINT NumDescriptors,
bool bShaderVisible = false)
{
D3D12_DESCRIPTOR_HEAP_DESC Desc;
Desc.Type = Type;
Desc.NumDescriptors = NumDescriptors;
Desc.Flags = (bShaderVisible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE);
HRESULT hr = pDevice->CreateDescriptorHeap(&Desc,
__uuidof(ID3D12DescriptorHeap),
(void**)&pDH);
if (FAILED(hr)) return hr;
hCPUHeapStart = pDH->GetCPUDescriptorHandleForHeapStart();
hGPUHeapStart = pDH->GetGPUDescriptorHandleForHeapStart();
HandleIncrementSize = pDevice->GetDescriptorHandleIncrementSize(Desc.Type);
return hr;
}
operator ID3D12DescriptorHeap*() { return pDH; }
D3D12_CPU_DESCRIPTOR_HANDLE hCPU(UINT index)
{
return hCPUHeapStart.MakeOffsetted(index,HandleIncrementSize);
}
D3D12_GPU_DESCRIPTOR_HANDLE hGPU(UINT index)
{
assert(Desc.Flags&D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);
return hGPUHeapStart.MakeOffsetted(index,HandleIncrementSize);
}
D3D12_DESCRIPTOR_HEAP_DESC Desc;
CComPtr<ID3D12DescriptorHeap> pDH;
D3D12_CPU_DESCRIPTOR_HANDLE hCPUHeapStart;
D3D12_GPU_DESCRIPTOR_HANDLE hGPUHeapStart;
UINT HandleIncrementSize;
};
Tópicos relacionados