Utilisation d'un tableau de textures dans DX12
J'ai réussi à créer du code, fonctionnant correctement en tant que Texture2DArray en hlsl en utilisant un seul ID3D12Resource et en le liant en tant que D3D12_SRV_DIMENSION_TEXTURE2DARRAY avec une taille de tableau constante.
std::pair<ComPtr<ID3D12Resource>, D3D12_SUBRESOURCE_DATA> ModelClass::GetTextureFromModel(const aiScene* scene, std::string filename, ComPtr<ID3D12Device2> device, ComPtr<ID3D12GraphicsCommandList4> commandList, int index)
{
D3D12_SUBRESOURCE_DATA textureDataSingle;
std::unique_ptr<uint8_t[]> decodedData;
ComPtr<ID3D12Resource> texture;
m_uploadHeaps.push_back({});
std::string s = std::regex_replace(filename, std::regex("\\\\"), "/");
std::wstring ws(s.begin(), s.end());
ThrowIfFailed(LoadWICTextureFromFileEx(device.Get(), ws.c_str(), 0, D3D12_RESOURCE_FLAG_NONE, WIC_LOADER_FORCE_RGBA32, texture.ReleaseAndGetAddressOf(), decodedData, textureDataSingle));
const UINT64 uploadBufferSize = GetRequiredIntermediateSize(texture.Get(), 0, 1);
// uploadHeap must outlive this function - until command list is closed
ThrowIfFailed(device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
D3D12_HEAP_FLAG_NONE,
&CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&m_uploadHeaps[m_uploadHeaps.size() - 1])
));
UpdateSubresources(commandList.Get(), texture.Get(), m_uploadHeaps[m_uploadHeaps.size() - 1].Get(), 0, 0, 1, &textureDataSingle);
if (texture->GetDesc().Width == 128 && texture->GetDesc().Height == 128)
{
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE));
D3D12_TEXTURE_COPY_LOCATION dst{};
dst.pResource = m_diffuseTextures[index].Get();
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst.SubresourceIndex = index;
D3D12_TEXTURE_COPY_LOCATION src{};
src.pResource = texture.Get();
commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
}
return { texture, textureDataSingle };
}
Cependant, il utilise la même description de ressource pour toutes les tranches de tableau (c.-à-d. Largeur et hauteur). J'ai remplacé le dernier "si" par le code ci-dessous:
{
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE));
D3D12_RESOURCE_DESC textureDesc = {};
textureDesc.MipLevels = 1;
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
textureDesc.Width = texture->GetDesc().Width;
textureDesc.Height = texture->GetDesc().Height;
textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
textureDesc.DepthOrArraySize = 1;
textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0;
textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
ThrowIfFailed(device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
D3D12_HEAP_FLAG_NONE,
&textureDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&m_diffuseTextures[index])
));
D3D12_TEXTURE_COPY_LOCATION dst{};
dst.pResource = m_diffuseTextures[index].Get();
D3D12_TEXTURE_COPY_LOCATION src{};
src.pResource = texture.Get();
commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
}
Je n'ai aucune erreur, donc je suppose que les données sont chargées correctement. Cependant, comment puis-je télécharger std :: vector ou std :: array <...> sur le GPU et l'utiliser avec Texture2D []?
Edit: @Nathan Reed J'essaie de télécharger plusieurs textures sur GPU, à utiliser dans le code shader (hlsl). Actuellement, j'utilise un ID3D12Resource unique avec la valeur choisie de "DepthOrArraySize" et une largeur et une hauteur fixes pour toutes les sous-ressources. Ensuite, je le traite comme Texture2DArray lors de la création de SRV. En conséquence, j'ai Texture2DArray dans mon hlsl qui fonctionne bien, mais l'exigence d'avoir une largeur / hauteur fixe pour tous les éléments n'est pas pratique. Je veux le remplacer par du code, ce qui me permet d'utiliser Texture2D [] en hlsl, où chaque texture peut avoir une taille différente. L'indexation dynamique n'est pas nécessaire.
Réponses
Je pense que ce que vous voulez pour cela, c'est créer un tableau de descripteurs qui répertorie vos textures. Les textures individuelles seraient créées et téléchargées en tant que Texture2D ordinaire. Vous avez configuré la signature racine de votre shader pour lier votre Texture2D[]HLSL à une plage contiguë de descripteurs SRV à partir d'un tas de descripteurs. Ensuite, lorsque vous créez les SRV pour vos textures, placez leurs descripteurs dans les emplacements correspondants du tas.
Pour plus de détails, vous pouvez consulter l' exemple D3D12DynamicIndexing dans le référentiel MS DirectX Graphics Samples. Je sais que vous avez dit que vous n'avez pas besoin d'indexation dynamique, mais la stratégie ici serait la même.
Merci Nathan! Je basais ma solution Texture2DArray sur l'exemple de dépôt MS que vous avez envoyé, mais après votre explication, il était beaucoup plus facile de convertir du code en Texture2D []. Pour tous ceux qui se demandent, voici le code:
void RaytracingResources::CreateDxrPipelineAssets(ID3D12Device5* device, ModelClass* model, std::vector<TextureWithDesc> texturesWithDesc, D3D12_SHADER_RESOURCE_VIEW_DESC indexDesc, D3D12_SHADER_RESOURCE_VIEW_DESC vertexDesc, std::vector<ResourceWithSize> buffersWithSize, std::vector<bool> isUAV)
{
// Create descriptor heaps
{
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
// Vertex + index + TLAS = 3
// Buffer count = y // buffersWithSize
// Number of textures = x // texturesWithDesc
int textureCount = 0;
for (const auto& tex : texturesWithDesc) {
textureCount += tex.resources.size();
}
desc.NumDescriptors = 3 + static_cast<UINT>(buffersWithSize.size()) + static_cast<UINT>(textureCount);
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
// Create the descriptor heap
ThrowIfFailed(device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_descriptorHeap)));
// Get the descriptor heap handle and increment size
D3D12_CPU_DESCRIPTOR_HANDLE handle = m_descriptorHeap->GetCPUDescriptorHandleForHeapStart();
UINT handleIncrement = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
// Create the CBV
// ...
// Create the DXR output buffer UAV
// ...
// Create the DXR Top Level Acceleration Structure SRV
// ...
// Create the index buffer SRV
// ...
// Create the vertex buffer SRV
// ...
// Create texture buffer SRV
for (auto& tex : texturesWithDesc)
{
for (auto& singleTextureResource : tex.resources)
{
if (tex.isSRV)
{
handle.ptr += handleIncrement;
device->CreateShaderResourceView(singleTextureResource.Get(), &tex.srvDesc, handle);
}
}
}
}
}
Comme l'a dit Nathan. Chaque texture est un descripteur distinct dans HLSL, donc je calcule le nombre de textures à lier, en fonction des données transmises. J'utilise un espace unique en supposant que les SRV Texture2D [] sont le dernier élément de l'espace tampon de texture dans HLSL. Pour l'instant, cela ne fonctionne que pour un seul tableau de textures, donc je vais devoir ajouter plus d'espaces pour permettre d'utiliser plusieurs tableaux de textures.