<p>I think what you want for this is to create a descriptor table which lists your textures. The individual textures would be created and uploaded as ordinary Texture2Ds. You'd set up the root signature of your shader to bind your <code>Texture2D[]</code> in HLSL to a contiguous range of SRV descriptors from a descriptor heap. Then, when you create the SRVs for your textures, put their descriptors into the corresponding slots in the heap.</p>
<p>For the details, you can look at the <a href="https://github.com/microsoft/DirectX-Graphics-Samples/tree/master/Samples/Desktop/D3D12DynamicIndexing" rel="nofollow noreferrer">D3D12DynamicIndexing</a> sample in MS's DirectX Graphics Samples repository. I know you said you don't need dynamic indexing, but the strategy here would be the same.</p>

CC BY-SA 4.0
2020-09-11T18:31:50.087Z
2020-09-11T18:31:50.087Z
Nathan Reed
<p>Thank you Nathan! I was basing my Texture2DArray solution on MS's sample repo that you've sent, but after your explanation it was much easier to convert code to Texture2D[]. For anyone wondering, here's code:</p>
<pre><code>void RaytracingResources::CreateDxrPipelineAssets(ID3D12Device5* device, ModelClass* model, std::vector&lt;TextureWithDesc&gt; texturesWithDesc, D3D12_SHADER_RESOURCE_VIEW_DESC indexDesc, D3D12_SHADER_RESOURCE_VIEW_DESC vertexDesc, std::vector&lt;ResourceWithSize&gt; buffersWithSize, std::vector&lt;bool&gt; 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&amp; tex : texturesWithDesc) {
            textureCount += tex.resources.size();
        }
        desc.NumDescriptors = 3 + static_cast&lt;UINT&gt;(buffersWithSize.size()) + static_cast&lt;UINT&gt;(textureCount);
        desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
        desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;

        // Create the descriptor heap
        ThrowIfFailed(device-&gt;CreateDescriptorHeap(&amp;desc, IID_PPV_ARGS(&amp;m_descriptorHeap)));

        // Get the descriptor heap handle and increment size
        D3D12_CPU_DESCRIPTOR_HANDLE handle = m_descriptorHeap-&gt;GetCPUDescriptorHandleForHeapStart();
        UINT handleIncrement = device-&gt;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&amp; tex : texturesWithDesc)
        {
            for (auto&amp; singleTextureResource : tex.resources)
            {
                if (tex.isSRV)
                {
                    handle.ptr += handleIncrement;
                    device-&gt;CreateShaderResourceView(singleTextureResource.Get(), &amp;tex.srvDesc, handle);
                }
            }
        }
    }
}
</code></pre>
<p>As Nathan said. Each texture is a separate descriptor in HLSL, so I'm calculating number of textures to bind, based on passed data. I am using single space with assumption that Texture2D[] SRVs are the last element in the texture buffer space in HLSL. For now it works only for single texture array, so I'll need to add more spaces to make it possible to use multiple array of textures.</p>

CC BY-SA 4.0
2020-09-12T08:27:28.883Z
2020-09-12T08:41:13.937Z
2020-09-12T08:41:13.937Z
DirectX_Programmer
<p>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.</p>
<pre><code>std::pair&lt;ComPtr&lt;ID3D12Resource&gt;, D3D12_SUBRESOURCE_DATA&gt; ModelClass::GetTextureFromModel(const aiScene* scene, std::string filename, ComPtr&lt;ID3D12Device2&gt; device, ComPtr&lt;ID3D12GraphicsCommandList4&gt; commandList, int index)
{
    D3D12_SUBRESOURCE_DATA textureDataSingle;
    std::unique_ptr&lt;uint8_t[]&gt; decodedData;
    ComPtr&lt;ID3D12Resource&gt; texture;
    m_uploadHeaps.push_back({});

    std::string s = std::regex_replace(filename, std::regex(&quot;\\\\&quot;), &quot;/&quot;);

    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-&gt;CreateCommittedResource(
        &amp;CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
        D3D12_HEAP_FLAG_NONE,
        &amp;CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),
        D3D12_RESOURCE_STATE_GENERIC_READ,
        nullptr,
        IID_PPV_ARGS(&amp;m_uploadHeaps[m_uploadHeaps.size() - 1])
    ));

    UpdateSubresources(commandList.Get(), texture.Get(), m_uploadHeaps[m_uploadHeaps.size() - 1].Get(), 0, 0, 1, &amp;textureDataSingle);

    if (texture-&gt;GetDesc().Width == 128 &amp;&amp; texture-&gt;GetDesc().Height == 128)
    {
        commandList-&gt;ResourceBarrier(1, &amp;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-&gt;CopyTextureRegion(&amp;dst, 0, 0, 0, &amp;src, nullptr);
    }

    return { texture, textureDataSingle };
}
</code></pre>
<p>However it uses same resource description for all array slices (i.e. width and height). I replaced last &quot;if&quot; with code below:</p>
<pre><code>{
    commandList-&gt;ResourceBarrier(1, &amp;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-&gt;GetDesc().Width;
    textureDesc.Height = texture-&gt;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-&gt;CreateCommittedResource(
        &amp;CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
        D3D12_HEAP_FLAG_NONE,
        &amp;textureDesc,
        D3D12_RESOURCE_STATE_COPY_DEST,
        nullptr,
        IID_PPV_ARGS(&amp;m_diffuseTextures[index])
    ));

    D3D12_TEXTURE_COPY_LOCATION dst{};
    dst.pResource = m_diffuseTextures[index].Get();

    D3D12_TEXTURE_COPY_LOCATION src{};
    src.pResource = texture.Get();

    commandList-&gt;CopyTextureRegion(&amp;dst, 0, 0, 0, &amp;src, nullptr);
}
</code></pre>
<p>I don't have any errors, so I assume that data is loaded correctly. However, how can I upload std::vector or std::array&lt;...&gt; to GPU and use it with Texture2D[]?</p>
<hr />
<p>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 &quot;DepthOrArraySize&quot; and fixed width and height for all subresources. Then I am treating it as Texture2DArray when creating SRV. As a result, I have <strong>Texture2DArray</strong> 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 <strong>Texture2D[]</strong> in hlsl, where each texture may have different size. Dynamic indexing is not necessary.</p>

CC BY-SA 4.0
2020-09-09T17:20:46.550Z
Sorry, this is really unclear - what do you mean "upload std::vector or std::array<...> to GPU and use it with Texture2D[]"? Can you add more details about what you're trying to achieve?
Nathan Reed
CC BY-SA 4.0
2020-09-09T18:36:22.227Z
@NathanReed I've added more detailed explanation at the end of question.
DirectX_Programmer
<texture><c++><hlsl><directx12>
Using array of textures in DX12
DirectX_Programmer
# Using array of textures in DX12

(Asked by: username_0 on 2020-09-08)

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: @username_1 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.

**Tags:** texture, c++, hlsl, directx12

> **Comments:**
> **username_1**: Sorry, this is really unclear - what do you mean "upload std::vector or std::array<...> to GPU and use it with Texture2D[]"? Can you add more details about what you're trying to achieve?  
> **username_0**: @username_1 I've added more detailed explanation at the end of question.  

---

## 2 answers

### Answer by username_1 on 2020-09-11. Score: 2 | Accepted answer

I think what you want for this is to create a descriptor table which lists your textures. The individual textures would be created and uploaded as ordinary Texture2Ds. You'd set up the root signature of your shader to bind your `Texture2D[]` in HLSL to a contiguous range of SRV descriptors from a descriptor heap. Then, when you create the SRVs for your textures, put their descriptors into the corresponding slots in the heap.

For the details, you can look at the [D3D12DynamicIndexing](https://github.com/microsoft/DirectX-Graphics-Samples/tree/master/Samples/Desktop/D3D12DynamicIndexing) sample in MS's DirectX Graphics Samples repository. I know you said you don't need dynamic indexing, but the strategy here would be the same.


---

### Answer by username_0 on 2020-09-12. Score: 0

Thank you username_1! I was basing my Texture2DArray solution on MS's sample repo that you've sent, but after your explanation it was much easier to convert code to Texture2D[]. For anyone wondering, here's 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);
                }
            }
        }
    }
}

```

As username_1 said. Each texture is a separate descriptor in HLSL, so I'm calculating number of textures to bind, based on passed data. I am using single space with assumption that Texture2D[] SRVs are the last element in the texture buffer space in HLSL. For now it works only for single texture array, so I'll need to add more spaces to make it possible to use multiple array of textures.


---

