Search code examples
c#directxwindows-8.1directx-11sharpdx

Saving a Texture2D using SharpDX when targeting Win8.1 + Metro?


I'm trying to save a user-generated Texture2D to disk, but it looks like the standard ways of accomplishing this aren't available when targeting DirectX11.1 / Win8.1 / Metro. ToStream/FromStream are absent, and the DX11 methods for writing a texture to disk are absent as well.

Any ideas or suggestions?


Solution

  • Here's the general solution I ended up with. Getting a DataStream through mapping a texture resource is what got me on the right track.

    General flow is create a texture with CpuAccessFlags.Read, then CopyResource from the source texture to the new texture, then read data from the new texture into a WIC Bitmap.

    public static class Texture2DExtensions
    {
        public static void Save(this Texture2D texture, IRandomAccessStream stream, DeviceManager deviceManager)
        {
            var textureCopy = new Texture2D(deviceManager.DeviceDirect3D, new Texture2DDescription
            {
                Width = (int)texture.Description.Width,
                Height = (int)texture.Description.Height,
                MipLevels = 1,
                ArraySize = 1,
                Format = texture.Description.Format,
                Usage = ResourceUsage.Staging,
                SampleDescription = new SampleDescription(1, 0),
                BindFlags = BindFlags.None,
                CpuAccessFlags = CpuAccessFlags.Read,
                OptionFlags = ResourceOptionFlags.None
            });
            deviceManager.ContextDirect3D.CopyResource(texture, textureCopy);
    
            DataStream dataStream;
            var dataBox = deviceManager.ContextDirect3D.MapSubresource(
                textureCopy,
                0,
                0,
                MapMode.Read,
                SharpDX.Direct3D11.MapFlags.None,
                out dataStream);
    
            var dataRectangle = new DataRectangle
            {
                DataPointer = dataStream.DataPointer,
                Pitch = dataBox.RowPitch
            };
    
            var bitmap = new Bitmap(
                deviceManager.WICFactory,
                textureCopy.Description.Width,
                textureCopy.Description.Height,
                PixelFormat.Format32bppBGRA,
                dataRectangle);
    
            using (var s = stream.AsStream())
            {
                s.Position = 0;
                using (var bitmapEncoder = new PngBitmapEncoder(deviceManager.WICFactory, s))
                {
                    using (var bitmapFrameEncode = new BitmapFrameEncode(bitmapEncoder))
                    {
                        bitmapFrameEncode.Initialize();
                        bitmapFrameEncode.SetSize(bitmap.Size.Width, bitmap.Size.Height);
                        var pixelFormat = PixelFormat.FormatDontCare;
                        bitmapFrameEncode.SetPixelFormat(ref pixelFormat);
                        bitmapFrameEncode.WriteSource(bitmap);
                        bitmapFrameEncode.Commit();
                        bitmapEncoder.Commit();
                    }
                }
            }
    
            deviceManager.ContextDirect3D.UnmapSubresource(textureCopy, 0);
            textureCopy.Dispose();
            bitmap.Dispose();
        }
    }