Search code examples
c#uwpsharpdx

when i try read renderd content from the texture of swapchain into byte[] on some pc's the returned array size bigger then expected


so the situation is like this
I use sharp dx to create a swap chain that linked to the XAML element SwapchainPanel now I have something rendered over it and then I try to grab rendered data into byte[] to place into an image buffer for that, I use this function ReadBuffer

    private D3D11.Texture2D OffscreenstagingTexture;
    private D3D11.Texture2D GetTexture(D3D11.Device _Device,
                             D3D11.DeviceContext _Context,
                             D3D11.Texture2DDescription _Desc)
    {
        if (OffscreenstagingTexture == null ||
            OffscreenstagingTexture.Description.Width != _Desc.Width ||
            OffscreenstagingTexture.Description.Height != _Desc.Height)
        {
            RemoveAndDispose(ref OffscreenstagingTexture);
            D3D11.Texture2DDescription _2DDesc = new D3D11.Texture2DDescription
            {
                Format = DXGI.Format.B8G8R8A8_UNorm,
                Height = _Desc.Height,
                Width = _Desc.Width,
                SampleDescription = new DXGI.SampleDescription(1, 0),
                ArraySize = _Desc.ArraySize,
                BindFlags = D3D11.BindFlags.None,
                CpuAccessFlags = D3D11.CpuAccessFlags.Read | D3D11.CpuAccessFlags.Write,
                Usage = D3D11.ResourceUsage.Staging,
                MipLevels = _Desc.MipLevels
            };
            OffscreenstagingTexture = ToDispose(new D3D11.Texture2D(_Device, _2DDesc));
        }

        return OffscreenstagingTexture;
    }


    public byte[] ReadBuffer(D3D11.Texture2D _2DTexture)
    {
        byte[] data = null;
        D3D11.Texture2DDescription _Desc = _2DTexture.Description;
        D3D11.Device _Device = _2DTexture.Device;
        D3D11.DeviceContext _Context = _Device.ImmediateContext;
        D3D11.Texture2D _2DMappedTexture = GetTexture(_Device, _Context, _Desc);
        try
        {
            _Context.CopyResource(_2DTexture, _2DMappedTexture);
            int size = _Desc.Width * _Desc.Height * 4;
            DataBox box = _Context.MapSubresource(_2DMappedTexture, 0, 0, D3D11.MapMode.Read, D3D11.MapFlags.None, out DataStream stream);
            data = ToByteArray(stream);
            stream.Dispose();
        }
        catch (Exception)
        {

        }
        return data;
    }

    private byte[] ToByteArray(Stream inputStream)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            inputStream.CopyTo(ms);
            return ms.ToArray();
        }
    }

now, on most of the pc, it works fine but there are some pc where SwapChainPanle is returning bigger byte[] than expected if I have 100 * 100 SwapChainPanel then the expected byte array size is 100 * 100 * 4 but it returns a bigger size array then that and because of that on some pc my app getting crashes and I have checked this same crash at my dell Vostro 3558 also


Solution

  • So I found the fix, I have to update the Readbuffer function

    public byte[] ReadBuffer(D3D11.Texture2D _2DTexture)
    {
        D3D11.Texture2DDescription _Desc = _2DTexture.Description;
        D3D11.Device _Device = _2DTexture.Device;
        D3D11.DeviceContext _Context = _Device.ImmediateContext;
        D3D11.Texture2D _2DMappedTexture = GetTexture(_Device, _Context, _Desc);
        _Context.CopyResource(_2DTexture, _2DMappedTexture);
        DataBox box = _Context.MapSubresource(_2DMappedTexture, 0, 0, D3D11.MapMode.Read, D3D11.MapFlags.None, out DataStream stream);
        var dataRectangle = new DataRectangle
        {
            DataPointer = stream.DataPointer,
            Pitch = box.RowPitch
        };
        var strid = _Desc.Width * 4;
        int size = _Desc.Width * _Desc.Height * 4;
        using (var bitmap = new Bitmap(manager.WICFactory,
                                       _2DMappedTexture.Description.Width,
                                       _2DMappedTexture.Description.Height,
                                       PixelFormat.Format32bppBGRA,
                                       dataRectangle))
        {
            var data = new byte[size];
            bitmap.CopyPixels(data, strid);
            _Context.UnmapSubresource(_2DMappedTexture, 0);
            return data;
        }
    }
    

    and it works like a charm