Texture Pitch

Started by
8 comments, last by nimoraca 15 years, 4 months ago
Hello, I need to create two float textures which have exactly the same values (except that one texture has usage DYNAMIC and the second STAGING). First I create the DYNAMIC texture:
	D3D10_TEXTURE2D_DESC alphaMapDesc;
ZeroMemory(&alphaMapDesc, sizeof(alphaMapDesc));
alphaMapDesc.Width		= verticesAlongSide;
alphaMapDesc.Height		= verticesAlongSide;
alphaMapDesc.MipLevels		= alphaMapDesc.ArraySize = 1;
alphaMapDesc.Format		= DXGI_FORMAT_R32G32B32A32_FLOAT; 
alphaMapDesc.SampleDesc.Count	= 1;
alphaMapDesc.SampleDesc.Quality = 0;
alphaMapDesc.Usage		= D3D10_USAGE_DYNAMIC;
alphaMapDesc.BindFlags		= D3D10_BIND_SHADER_RESOURCE;
alphaMapDesc.CPUAccessFlags	= D3D10_CPU_ACCESS_WRITE;
alphaMapDesc.MiscFlags		= 0;
d3d10Device->CreateTexture2D(&alphaMapDesc, NULL, &alphaMap);

Then I create the second (STAGING) texture filled with 0's with exactly the same values:
alphaMapDesc.Usage =  D3D10_USAGE_STAGING;
alphaMapDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
alphaMapDesc.BindFlags	    = 0;

D3D10_SUBRESOURCE_DATA initialData;
float* texelData = new float[verticesAlongSide * verticesAlongSide * 4];
ZeroMemory(texelData, verticesAlongSide * verticesAlongSide * 4 * sizeof(float));
initialData.pSysMem		= texelData;
initialData.SysMemPitch		= verticesAlongSide * 4 * sizeof(float);
initialData.SysMemSlicePitch	= 0;
d3d10Device->CreateTexture2D(&alphaMapDesc, &initialData, &alphaMapConsistent);

I thought the SysMemPitch is the width of one row in bytes, so I set it to verticesAlongSide * 4 * sizeof(float) (the texture has a width of verticesAlongSide texels and every texel has four floats). Since both textures are basically the same I assumed that they both have the same pitch values. Just to be sure I checked the pitch of the first texture:

alphaMap->Map(D3D10CalcSubresource(0, 0, 1), D3D10_MAP_WRITE_DISCARD, 0, &mappedAlphaMap);
UINT pitch = mappedAlphaMap.RowPitch;

But surprisingly they have different pitch values! The second texture (where I manually set the pitch) has a pitch of 8208 (verticesAlongSide = 513, thus: 513*4*4) and the first texture has a pitch of 16384. Does anyknow know why the first texture has a pitch of 16384? Is my calculated pitch of 8208 wrong?
Advertisement
The pitch is the distance from the begin of one line to the next line. It’s not necessary equal to the size of a line as the hardware can decide to use a different data layout.

To make things even more complicate you should only write to the bytes that are part of the actual texture as the graphics adapter may use the padding bytes for other things.
Hm, well ok, so DX adds some bytes at the end of each line and so I get the "strange" pitch of 16384 for the first texture.

But is my pitch value for the second texture correct? (verticesAlongSide * 4 * sizeof(float) for a texture of size verticesAlongSide x verticesAlongSide with R32G32B32A32_FLOAT)?
It’s not the pitch it’s the size of a line you have calculated.
Quote:Original post by Demirug
It’s not the pitch it’s the size of a line you have calculated.

Yes, because if these "extra bytes" at the end of each line is 0 then the pitch size is equal to the size of on line. How should I know how many "extra bytes" DX10 expects? If my pitch calculation is wrong, how would the correct calculation look like?
If you provide the data during creation or an UpdateResource Direct3D will use the pitch that you set. If the internal pitch is different from your pitch the runtime/driver is responsible to copy your data to the right places. Therefore if you use the line size as pitch during resource creation or updating you are fine. Direct3D just offers you the option to use a different pitch in the case your data is padded.
Hm, I made 2 tests:
I created the texture with a pitch of 8208 (verticesAlongSide *4 * sizeof(float)), then I called Map() on the texture and read the value of RowPitch. It is: 8256.

Then I created the texture with exact the same settings, but this time I (randomly) set the pitch to 1 (which makes no sense at all). Again I mapped the texture and read back the RowPitch and it was again 8256.

So what is the sense of parameter SysMemPitch if DirectX calculates its own pitch anyway? (It seems like I could you any value)
Quote:Original post by schupf
So what is the sense of parameter SysMemPitch if DirectX calculates its own pitch anyway? (It seems like I could you any value)

Let's say you have a 512x512 image, but you want to create a 256x256 texture from the top left part.

The trivial option is to create a new 256x256 array, and copy your data to it. Then you'd lock the destination texture, and copy the data to it in one memcpy. The pitch would then be 256xpixelSize, but you had to copy your data once just to get it to the right size. Of course, there's a much simpler way.

If you pass a pointer to the start of the first row, and provide a pitch of 512*pixelsize, DX will automagically load just the top left part. Why? because each row is 256 pixels wide. When DX finishes reading the first row, it will skip 512*pixelSize bytes forward (the pitch you provided), landing at the start of the second row in the bigger source image.
By the time it finishes 256 rows, it would have read the entire top left corner of the source image, and copied it to the new texture.

This works great for any part of a bigger image, not just the top left. And, in fact, this is exactly why DX returns a pitch value when you map a texture. If you map just part of the texture, the pitch returned allows DX to let you modify the memory directly where it is. If DX had to return all memory in a single consecutive unit, it would have had to copy the data to a new array, give it to you, and then copy it back to the right place after an Unmap. This is clearly very wasteful, and that's what memory pitch values are for, both when you pass data to DX and when DX returns data for you.

Hope this helps.
Sirob Yes.» - status: Work-O-Rama.
Ok things getting clearer now!

Quote:If you pass a pointer to the start of the first row, and provide a pitch of 512*pixelsize, DX will automagically load just the top left part. Why? because each row is 256 pixels wide. When DX finishes reading the first row, it will skip 512*pixelSize bytes forward (the pitch you provided), landing at the start of the second row in the bigger source image.
By the time it finishes 256 rows, it would have read the entire top left corner of the source image, and copied it to the new texture.

Just to be sure: You mean the following:
D3D10_TEXTURE2D_DESC tex256; // 256 x 256 destination texturetex256.Width = tex256.Height = 256;//... set all other parametersD3D10_SUBRESOURCE_DATA initialData;initialData.pSysMem		= texelDataFrom512x512Texture; // This is a pointer to the data of the 512 x 512 source texture received by calling Map() on the 512x512 textureinitialData.SysMemPitch		= 512 * texelData512x512;initialData.SysMemSlicePitch	= 0;d3d10Device->CreateTexture2D(&tex256, &initialData, &texture256);

And DX will basically perform this operation (pseudocode):
for(int i=0; i < tex256.Height; i++) {   memcpy(tex256.texelData + i*tex256.Width*tex256TexelSize,           tex512.texelData + i*initialData.SysMemPitch, tex256.Width*tex256TexelSize);

So it reads "byte size of one row of the destination texture" bytes of the source texture, copies it to the source texture and then advances the read pointer (of the source texture) about the delivered pitch of the structure D3D10_SUBRESOURCE_DATA (here 512*texelSizeDestTexture) to read the next line and so on. Is this correct?

Quote:This works great for any part of a bigger image, not just the top left.

I don't understand how you could read any part of a bigger texture except the top left part. I mean in order to read the top right part DirectX had to start reading in the middle of the first row but I cant see any way to tell DX to do so?!

Quote:And, in fact, this is exactly why DX returns a pitch value when you map a texture. If you map just part of the texture, the pitch returned allows DX to let you modify the memory directly where it is. If DX had to return all memory in a single consecutive unit, it would have had to copy the data to a new array, give it to you, and then copy it back to the right place after an Unmap. This is clearly very wasteful, and that's what memory pitch values are for, both when you pass data to DX and when DX returns data for you.

I understood that the pitch can be used to copy a part of a bigger texture to a new smaller texture but I still can't see the sense of the pitch AFTER the copy is executed. All I need are the texels so why should I need these "extra bytes" at the end of each row after the texture is created?
What about the pitch when I use block compression. Is it the size of one row of 4x4 blocks, or what?

This topic is closed to new replies.

Advertisement