I managed to create code, working correctly as Texture2DArray in hlsl by using single ID3D12Resource and binding it as D3D12_SRV_DIMENSION_TEXTURE2DARRAY with constant array size.
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 };
}
However it uses same resource description for all array slices (i.e. width and height). I replaced last "if" with code below:
{
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);
}
I don't have any errors, so I assume that data is loaded correctly. However, how can I upload std::vector or std::array<...> to GPU and use it with Texture2D[]?
Edit: @Nathan Reed I am trying to upload multiple textures to GPU, to use in shader code (hlsl). Currently I am using single ID3D12Resource with chosen value of "DepthOrArraySize" and fixed width and height for all subresources. Then I am treating it as Texture2DArray when creating SRV. As a result, I have Texture2DArray in my hlsl which works fine, but requirement of having fixed width/height for all elements is not convenient. I want to replace it with code, which enable me to use Texture2D[] in hlsl, where each texture may have different size. Dynamic indexing is not necessary.