How to initialize Texture2DArray?

Started by
6 comments, last by Volgogradetzzz 9 years, 1 month ago

Hello.

I'm using DirectXTK for texture creation from *.dds. Thought documentation says that DDSTextureLoader supports texture arrays, I couldn't figure out how to create an array. So I'm loading textures with D3DReadFileToBlob() and creating texture from it with CreateDDSTextureFromMemory(). And now interesting part - this code works fine:


CreateDDSTextureFromMemory(device, static_cast<uint8_t*>(textureBlob1->GetBufferPointer()), textureBlob1->GetBufferSize(), texture.ReleaseAndGetAddressOf(), nullptr);

D3D11_TEXTURE2D_DESC texElementDesc;
texture->GetDesc(&texElementDesc);

D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
viewDesc.Format = texElementDesc.Format;
viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
viewDesc.Texture2D.MostDetailedMip = 0;
viewDesc.Texture2D.MipLevels = 1;
    
hr = device->CreateShaderResourceView(texture.Get(), &viewDesc, textureView.ReleaseAndGetAddressOf());

But this is only single texture. Let's change it for an array:


CreateDDSTextureFromMemory(device, static_cast<uint8_t*>(textureBlob1->GetBufferPointer()), textureBlob1->GetBufferSize(), texture.ReleaseAndGetAddressOf(), nullptr);

D3D11_TEXTURE2D_DESC texElementDesc;
texture->GetDesc(&texElementDesc);

D3D11_TEXTURE2D_DESC texArrayDesc;
texArrayDesc.Width = texElementDesc.Width;
texArrayDesc.Height = texElementDesc.Height;
texArrayDesc.MipLevels = 1;
texArrayDesc.ArraySize = 1;
texArrayDesc.Format = texElementDesc.Format;
texArrayDesc.SampleDesc.Count = 1;
texArrayDesc.SampleDesc.Quality = 0;
texArrayDesc.Usage = D3D11_USAGE_DEFAULT;
texArrayDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texArrayDesc.CPUAccessFlags = 0;
texArrayDesc.MiscFlags = 0;

D3D11_SUBRESOURCE_DATA resourceData1{};
resourceData1.pSysMem = static_cast<uint8_t*>(textureBlob1->GetBufferPointer());
resourceData1.SysMemPitch = texElementDesc.Width * sizeof(uint8_t) * 4;
resourceData1.SysMemSlicePitch = texElementDesc.Width * texElementDesc.Height * sizeof(uint8_t) * 4;

ComPtr<ID3D11Texture2D> texArray;
hr = device->CreateTexture2D(&texArrayDesc, &resourceData1, texArray.ReleaseAndGetAddressOf());

D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
viewDesc.Format = texArrayDesc.Format;
viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
viewDesc.Texture2DArray.MostDetailedMip = 0;
viewDesc.Texture2DArray.MipLevels = 1;
viewDesc.Texture2DArray.FirstArraySlice = 0;
viewDesc.Texture2DArray.ArraySize = 1;

hr = device->CreateShaderResourceView(texArray.Get(), &viewDesc, &textureView);

And, as you might guess, this doesn't work. Actually this work, but somewhat strange - some textures looks cutted, some become fully transparent. Personally me think that the problem is here:


D3D11_SUBRESOURCE_DATA resourceData1{};
resourceData1.pSysMem = static_cast<uint8_t*>(textureBlob1->GetBufferPointer());
resourceData1.SysMemPitch = texElementDesc.Width * sizeof(uint8_t) * 4;
resourceData1.SysMemSlicePitch = texElementDesc.Width * texElementDesc.Height * sizeof(uint8_t) * 4;

I know there's a way to update texture with context's update sub resource. But I'm interested in initializing texture on creation.

Advertisement

But this is only single texture. Let's change it for an array:


…
texArrayDesc.ArraySize = 1;


…
viewDesc.Texture2DArray.ArraySize = 1;

You aren’t likely to have any success creating texture arrays when you are hard-coding it not to be an array.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

ALWAYS read the Remarks section on MSDN: ID3D11Device::CreateTexture2D method.

You aren’t likely to have any success creating texture arrays when you are hard-coding it not to be an array.

I specified D3D11_SRV_DIMENSION_TEXTURE2DARRAY view dimension, so ArraySize = 1 is valid I think.

ALWAYS read the Remarks section on MSDN

I read this but it doesn't applies to my case - I don't have mips and my textures are the same size. And actually I'm testing with 1 texture.

I figured it out. I was right, all the magic inside this lines:


D3D11_SUBRESOURCE_DATA resourceData1{};
resourceData1.pSysMem = static_cast<uint8_t*>(textureBlob1->GetBufferPointer());
resourceData1.SysMemPitch = texElementDesc.Width * sizeof(uint8_t) * 4;
resourceData1.SysMemSlicePitch = texElementDesc.Width * texElementDesc.Height * sizeof(uint8_t) * 4;

The blob holds ALL data. For *.dds file it's also information in header. I investigated DirectXTK sources and found that they take the header length into account when assign a data. This is fixed code that works:


ptrdiff_t offset = sizeof(uint32_t) + sizeof(DDS_HEADER);

D3D11_SUBRESOURCE_DATA resourceData1{};
resourceData1.pSysMem = (static_cast<uint8_t*>(textureBlob1->GetBufferPointer()) + offset);
resourceData1.SysMemPitch = texElementDesc.Width * sizeof(uint8_t) * 4;
resourceData1.SysMemSlicePitch = texElementDesc.Width * texElementDesc.Height * sizeof(uint8_t) * 4;

The DDS_HEADER definition can be found in dds.h header in toolkit sources.

I specified D3D11_SRV_DIMENSION_TEXTURE2DARRAY view dimension, so ArraySize = 1 is valid I think.

int iAnt[1]; is valid too. An array with a single element isn’t actually an array though, aside from syntax.

I figured it out. I was right, all the magic inside this lines:

Since you hard-coded the array size to 1 and only passed a single D3D11_SUBRESOURCE_DATA pointer to ID3D11Device::CreateTexture2D(), I doubt very much that you’ve gotten anything working other than a single texture that you’re calling an “array” just because you managed to slap a “[1]” on it, even though that didn’t actually change anything about the texture being a single image like every other texture you’ve loaded.
You have nothing to celebrate until you can access texture-array indices [0] and [1], etc.

L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

L. Spiro, I can't agree with you, sorry.

What makes a resource view to act like texture array is exactly D3D11_SRV_DIMENSION_TEXTURE2DARRAY. And I'm so assured because my hardcoded values (i.e. ArraySize = 1) is a simple snippet for forum only. In my code I have more than 1 texture and texture array behaved bad in all cases despite the size.

Btw, your art on devianart is amazing. You're definitely a very talented person ).

Update. Everything is much more simple. It turned out that dds format supports several textures in one file. And CreateDDSTextureFromMemory() do all the job. All we need to do is just create dds with texassemble tool (https://directxtex.codeplex.com/wikipage?title=Texassemble) and supply to texture creation function.

This topic is closed to new replies.

Advertisement