Reading Datastream sharpDX Error all values are 0
Asked Answered
H

1

1

I followed this solution for my project : How to create bitmap from Surface (SharpDX)

I don't have enough reputation to comment so I'm opening a new question here.

My project is basically in Direct 2D, I have a Surface buffer, a swapchain. I want to put my buffer into a datastream and reads it's value to put it into a bitmap and save it on disk ( like a screen capture), but my code won't work since all the bytes values are 0 (which is black) and this doesn't make sense since my image is fully white with a bit of blue.

Here is my code :

SwapChainDescription description = new SwapChainDescription()
     {
        ModeDescription = new ModeDescription(this.Width, this.Height, new Rational(60, 1), Format.B8G8R8A8_UNorm),
        SampleDescription = new SampleDescription(1, 0),
        Usage = Usage.RenderTargetOutput,
        BufferCount = 1,
        SwapEffect = SwapEffect.Discard,
        IsWindowed = true,
        OutputHandle = this.Handle
     };

     Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.Debug | DeviceCreationFlags.BgraSupport, description, out device, out swapChain);

     SharpDX.DXGI.Device dxgiDevice = device.QueryInterface<SharpDX.DXGI.Device>();
     SharpDX.DXGI.Adapter dxgiAdapter = dxgiDevice.Adapter;

     SharpDX.Direct2D1.Device d2dDevice = new SharpDX.Direct2D1.Device(dxgiDevice);
     d2dContext = new SharpDX.Direct2D1.DeviceContext(d2dDevice, SharpDX.Direct2D1.DeviceContextOptions.None);
     SharpDX.Direct3D11.DeviceContext d3DeviceContext = new SharpDX.Direct3D11.DeviceContext(device);




     properties = new BitmapProperties(new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied),
          96, 96);

     Surface backBuffer = swapChain.GetBackBuffer<Surface>(0);
     d2dTarget = new SharpDX.Direct2D1.Bitmap(d2dContext, backBuffer, properties);

     d2dContext.Target = d2dTarget;

     playerBitmap = this.LoadBitmapFromContentFile(@"C:\Users\ndesjardins\Desktop\wave.png");

     //System.Drawing.Bitmap bitmapCanva = new System.Drawing.Bitmap(1254, 735);

     d2dContext.BeginDraw();
     d2dContext.Clear(SharpDX.Color.White);
     d2dContext.DrawBitmap(playerBitmap, new SharpDX.RectangleF(0, 0, playerBitmap.Size.Width, playerBitmap.Size.Height), 1f, SharpDX.Direct2D1.BitmapInterpolationMode.NearestNeighbor);
     SharpDX.Direct2D1.SolidColorBrush brush = new SharpDX.Direct2D1.SolidColorBrush(d2dContext, SharpDX.Color.Green);
     d2dContext.DrawRectangle(new SharpDX.RectangleF(200, 200, 100, 100), brush);
     d2dContext.EndDraw();

     swapChain.Present(1, PresentFlags.None);


     Texture2D backBuffer3D = backBuffer.QueryInterface<SharpDX.Direct3D11.Texture2D>();

     Texture2DDescription desc = backBuffer3D.Description;
     desc.CpuAccessFlags = CpuAccessFlags.Read;
     desc.Usage = ResourceUsage.Staging;
     desc.OptionFlags = ResourceOptionFlags.None;
     desc.BindFlags = BindFlags.None;

     var texture = new Texture2D(device, desc);

     d3DeviceContext.CopyResource(backBuffer3D, texture);

     byte[] data = null;
     using (Surface surface = texture.QueryInterface<Surface>())
     {
        DataStream dataStream;
        var map = surface.Map(SharpDX.DXGI.MapFlags.Read, out dataStream);
        int lines = (int)(dataStream.Length / map.Pitch);
        data = new byte[surface.Description.Width * surface.Description.Height * 4];

        dataStream.Position = 0;
        int dataCounter = 0;
        // width of the surface - 4 bytes per pixel.
        int actualWidth = surface.Description.Width * 4;
        for (int y = 0; y < lines; y++)
        {
           for (int x = 0; x < map.Pitch; x++)
           {
              if (x < actualWidth)
              {
                 data[dataCounter++] = dataStream.Read<byte>();
              }
              else
              {
                 dataStream.Read<byte>();
              }
           }
        }
        dataStream.Dispose();
        surface.Unmap();

        int width = surface.Description.Width;
        int height = surface.Description.Height;
        byte[] bytewidth = BitConverter.GetBytes(width);
        byte[] byteheight = BitConverter.GetBytes(height);

        Array.Copy(bytewidth, 0, data, 0, 4);
        Array.Copy(byteheight, 0, data, 4, 4);

     }

Do you guys have any idea why the byte array that is returned at the end is full of 0 since it should be mostly 255? All I did in my backbuffer was to draw a bitmap image and a rectangle form. Array.Copy is to add the width and height header to the byte array, therefore I could create a bitmap out of it.

Hittel answered 4/7, 2017 at 14:43 Comment(0)
N
0

I answered in a comment but formatting is horrible so apologies!

https://gamedev.stackexchange.com/a/112978/29920 This looks promising but as you said in reply to mine, this was some time ago and I'm pulling this out of thin air, if it doesn't work either someone with more current knowledge will have to answer or I'll have to grab some source code and try myself.

SharpDX.Direct2D1.Bitmap dxbmp = new SharpDX.Direct2D1.Bitmap(renderTarget, 
new SharpDX.Size2(bmpWidth, bmpHeight), new 
BitmapProperties(renderTarget.PixelFormat));
dxbmp.CopyFromMemory(bmpBits, bmpWidth * 4);

This looks kind of like what you need. I'm assuming bmpBits in here is either a byte array or a memory stream either of which could then be saved off or at least give you something to look at to see if you're actually getting pixel data

Nagano answered 5/7, 2017 at 15:17 Comment(2)
Thanks, copyFromMemory does exactly the trick ! I was also wondering if it was possible to convert a bitmap from System.Drawing.Bitmap to a sharpDX.Direct2D1.Bitmap in like less than 5ms ?Hittel
I'm not sure. The link in my previous reply does something with loading a SharpDX bitmap (I think) so you might just have to get creative. If you need to load a bitmap quickly you could look at doing it asynchronously? Read from file and convert it to a byte array (or whatever SharpDX requires it to be) before giving it up to the main thread? It wouldn't take any less time of course but you free up your main thread while it does it's business - is that an option? Also if you're happy with the above answer, could you mark it as such? It could help someone else in the future :)Nagano

© 2022 - 2024 — McMap. All rights reserved.