Reading from a staging 2D texture array in DirectX10

I have a DX10 program, where I create an array of 3 16x16 textures, then map, read, and unmap each subresource in turn. I use a single mip level, set resource usage to staging and CPU access to read. Now, here is the problem:

• Subresource 0 contains 1024 bytes, pitch 64, as expected.
• Subresource 1 contains 512 bytes, pitch 64.
• Subresource 2 contains 256 bytes, pitch 64.

I expect all three to be the same size. Debugging output is enabled, but not reporting any warnings or errors. Am I missing something, or might this be some sort of driver issue?

Here is the code. The language is Nemerle, but C# and C++ would look almost the same. I have looked through the generated code, and am fairly confident the problem is not language-related.

def cpuTexture = Texture2D
( device
, Texture2DDescription() <-
{
Width     = 16;
Height    = 16;
MipLevels = 1;
ArraySize = 3;
Format    = Format.R32_Float;
Usage     = ResourceUsage.Staging;
SampleDescription = SampleDescription(count = 1, quality = 0);
}
);
foreach (subresource in [0 .. 2])
{
def data = cpuTexture.Map(subresource, MapMode.Read, MapFlags.None);
Console.WriteLine($"subresource$subresource");
Console.WriteLine($"length =$(data.Data.Length)");
Console.WriteLine($"pitch =$(data.Pitch)");
cpuTexture.Unmap(subresource);
}

• Can you post your code for initializing and mapping the texture array? – Nathan Reed Apr 20 '12 at 0:11
• @NathanReed, sure, added the code. – Don Reba Apr 20 '12 at 4:05
• Thanks. Your code looks right as far as I can see, though, and I checked against the D3D10 docs as well. I'm afraid I have no idea what's going on. :( – Nathan Reed Apr 20 '12 at 4:24
• Is the Texture2D class part of a framework or did you code it yourself? If yes, can you provide the code for cpuTexture.Map(...) ? – Djindjidj Dec 15 '16 at 13:50
• @Djindjidj, it's part of the SlimDX library — a thin wrapper around DirectX. – Don Reba Dec 15 '16 at 14:47

You're forgetting to consider mipLevels. When creating a texture, usually miplevels will be generated so you will not find texture element 2 at subresource 2 (there is a mipLevel in it, which is half of original texture and so on).

Use this function to get the right subresource index.

    ID3D11Texture2D *cpuTexture = NULL;

D3D11_TEXTURE2D_DESC cputextdesc;
memset(&cputextdesc,0,sizeof(cputextdesc));

cputextdesc.Width = cputextdesc.Height = 16;
cputextdesc.ArraySize = 3;
cputextdesc.MipLevels = 1;
cputextdesc.Format = DXGI_FORMAT_R32_FLOAT;
cputextdesc.Usage = D3D11_USAGE_STAGING;
cputextdesc.SampleDesc.Count = 1;
cputextdesc.SampleDesc.Quality = 0;

device->CreateTexture2D(&cputextdesc,NULL,&cpuTexture);

int text1 = D3D11CalcSubresource(0,0,1);
int text2 = D3D11CalcSubresource(0,1,1);
int text3 = D3D11CalcSubresource(0,2,1);

D3D11_MAPPED_SUBRESOURCE mres1,mres2,mres3;

// (assert row and depth pitch are equals)

icontext->Unmap(cpuTexture,text1);
icontext->Unmap(cpuTexture,text2);
icontext->Unmap(cpuTexture,text3);

• There is only a single mip level. – Don Reba Jun 13 '12 at 21:04
• I modified my answer with a code example. 3 subresource have the same row and depth pitch. – Vincenzo Jun 14 '12 at 6:48
• Still incorrect because "MipLevels = 1" in the OP, and besides - if it were mipmapping, the lengths would be quartering, not halving, for each subresource (the pitch would be expected to - but may not always - halve). I suspect it's more likely a problem in the calculation of "data.Data.Length" in the OP's environment. – Maximus Minimus Sep 12 '12 at 15:37

We can begin by stating that this problem is certainly either language-related or a SlimDX bug; it is absolutely not a driver bug. Let's see if we can find out which.

The canonical implementation of ID3D10Texture2D::Map is described on MSDN, and we see that the method signature is:

HRESULT Map(
[in]  UINT                   Subresource,
[in]  D3D10_MAP              MapType,
[in]  UINT                   MapFlags,
[out] D3D10_MAPPED_TEXTURE2D *pMappedTex2D
);


When we look at the D3D10_MAPPED_TEXTURE2D struct we see that it contains the following members:

typedef struct D3D10_MAPPED_TEXTURE2D {
void *pData;
UINT RowPitch;
} D3D10_MAPPED_TEXTURE2D;


From this we can categorically state that the Length member you are accessing (data.Data.Length) does not exist in Microsoft's Direct3D runtime and therefore cannot be provided by the driver.

When we cross-check with the SlimDX source code we see that the return from Map is indeed constructed by SlimDX itself:

int mipHeight = GetMipSize( mipSlice, desc.Height );
int sizeInBytes = mipHeight * mappedRect.RowPitch;
if (Utilities::IsCompressed(desc.Format))
sizeInBytes /= 4;

return gcnew SlimDX::DataRectangle( mappedRect.RowPitch, gcnew DataStream( mappedRect.pData, sizeInBytes, true, true, false ) );


This is therefore a SlimDX bug.

Looking over the SlimDX code I've linked I don't immediately see anything that could cause it, so I would suggest updating you download of SlimDX as a first troubleshooting step, as it may be a bug that has been fixed by a more recent version.

• There is a good chance it was fixed in the five years since I asked the question. :) – Don Reba Jun 12 '17 at 10:22