Is the SlicePitch value wrong?

50 Views Asked by At

I have been trying to copy the contents from a Texture2DArray using Device.ImmediateContext.Mapsubresource(). I have done this multiple times on my old laptop and it worked fine, but when I did it using Intel Iris Xe Graphics for some reason there are gaps of zeros in the middle.

This is a sample code for it:

[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);

public static unsafe float[] GetData()
{
    int gpuAdapterIndex = 0;

    SharpDX.DXGI.Adapter1 gpu;
    using (var factory = new SharpDX.DXGI.Factory1())
    {
        gpu = factory.GetAdapter1(gpuAdapterIndex);
    }

    Device device = new Device(gpu, DeviceCreationFlags.Debug);

    int pixelSize = sizeof(float);
    int width = 10;
    int height = 19;
    int depth = 3;
    float[] data = new float[width * height * depth];
    for (int i = 0; i < data.Length; i++)
    {
        data[i] = i;  
    }

    DataRectangle[] rectangles = new DataRectangle[depth];

    fixed (float* dataPtr = data)
    {
        IntPtr p = (IntPtr)dataPtr;

        for (int i = 0; i < rectangles.Length; i++)
        {
            rectangles[i] = new DataRectangle(IntPtr.Add(p, width * height * pixelSize * i), width * pixelSize);
        }
    }

    Texture2D t = new Texture2D(device, new Texture2DDescription()
    {
        ArraySize = depth,
        CpuAccessFlags = CpuAccessFlags.Write | CpuAccessFlags.Read,
        BindFlags = BindFlags.None,
        Format = SharpDX.DXGI.Format.R32_Float,
        Height = height,
        Width = width,
        MipLevels = 1,
        Usage = ResourceUsage.Staging,
        SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
        OptionFlags = ResourceOptionFlags.None,
    }, rectangles);

    float[] output = new float[data.Length];

    DataBox box = device.ImmediateContext.MapSubresource(t, 0, MapMode.Read, MapFlags.None);

    fixed (float* o = output)
    {
        IntPtr dst = (IntPtr)o;
        IntPtr scr = box.DataPointer;

        for (int z = 0; z < depth; z++)
        {
            for (int y = 0; y < height; y++)
            {
                CopyMemory(dst, scr, (uint)(width * pixelSize));

                scr = IntPtr.Add(scr, box.RowPitch);
                dst = IntPtr.Add(dst, width * pixelSize);
            }
        }
    }

    device.ImmediateContext.UnmapSubresource(t, 0);

    t.Dispose();
    device.Dispose();

    return output;
}

When I check box.SlicePitch and compare it to the actual size of each slice, they were different which, if I am not wrong, is not supposed to happen.

(width,height), box.rowpitch, box.slicepitch, real slice pitch
(2, 38), 64, 2432, 2560
(3, 38), 64, 2432, 2560
(4, 38), 64, 2432, 2560
(5, 38), 64, 2432, 2560
(6, 38), 64, 2432, 2560
(7, 38), 64, 2432, 2560
(8, 38), 64, 2432, 2560
(9, 38), 64, 2432, 2560
(10, 38), 64, 2432, 2560
(11, 38), 64, 2432, 2560
(12, 38), 64, 2432, 2560
(13, 38), 64, 2432, 2560
(14, 38), 64, 2432, 2560
(15, 38), 64, 2432, 2560
(17, 38), 128, 4864, 5120
(18, 38), 128, 4864, 5120
(19, 38), 128, 4864, 5120
(20, 38), 128, 4864, 5120
(21, 38), 128, 4864, 5120
(22, 38), 128, 4864, 5120
(23, 38), 128, 4864, 5120
(24, 38), 128, 4864, 5120
(25, 38), 128, 4864, 5120
(26, 38), 128, 4864, 5120
(27, 38), 128, 4864, 5120
(28, 38), 128, 4864, 5120
(29, 38), 128, 4864, 5120
(30, 38), 128, 4864, 5120
(31, 38), 128, 4864, 5120
(33, 38), 192, 7296, 7680
(34, 38), 192, 7296, 7680
(35, 38), 192, 7296, 7680
(36, 38), 192, 7296, 7680
(37, 38), 192, 7296, 7680
(38, 38), 192, 7296, 7680
(39, 38), 192, 7296, 7680
(40, 38), 192, 7296, 7680

This does not happen with any other graphics card I have (Intel graphics HD 520 and nvidia mx450). It appears that what is happening is that instead of calculating the slice pitch to be height * box.RowPitch it rounds the height to the nearest multiple of 4 above it and then multiply it by box.RowPitch. My biggest concern is can this happen in other cases? If so then is there is a general way to deal with them?

1

There are 1 best solutions below

5
wd357dui On

can this happen in other cases?

yes, pitch size can be adjusted in favor of memory alignment or compression, D3D11 does not enforce that every hardware does it the same way, and also this concept is not limited to DirectX; your current graphics card didn't do anything wrong, it simply opted for alignment.

is there a general way to deal with them?

just do not assume that every subresource or their row & depth are placed consistently right next to each other in memory. you should handle each block of memory (in your case, each row) separately.