2016-05-08 2 views
1

Conversion d'un .Net Bitmap à un SlimDX Texture2D fonctionne très vite comme ceci: http://www.rolandk.de/index.php?option=com_content&view=article&id=65:bitmap-from-texture-d3d11&catid=16:blog&Itemid=10Convertir SlimDX.Direct3D11 Texture2D à .Net Bitmap

private Texture2D TextureFromBitmap(FastBitmapSingle fastBitmap) 
{ 
    Texture2D result = null; 
    DataStream dataStream = new DataStream(fastBitmap.BitmapData.Scan0, fastBitmap.BitmapData.Stride * fastBitmap.BitmapData.Height, true, false); 
    DataRectangle dataRectangle = new DataRectangle(fastBitmap.BitmapData.Stride, dataStream); 
    try 
    { 
     Texture2DDescription dt = new Texture2DDescription 
     { 
      BindFlags = BindFlags.ShaderResource, 
      CpuAccessFlags = CpuAccessFlags.None, 
      Format = Format.B8G8R8A8_UNorm, 
      OptionFlags = ResourceOptionFlags.None, 
      MipLevels = 1, 
      Usage = ResourceUsage.Immutable, 
      Width = fastBitmap.Size.X, 
      Height = fastBitmap.Size.Y, 
      ArraySize = 1, 
      SampleDescription = new SampleDescription(1, 0), 
     }; 
     result = new Texture2D(device, dt, dataRectangle); 
    } 
    finally 
    { 
     dataStream.Dispose(); 
    } 
    return result; 
} 

Pour convertir la texture vers un .Net Bitmap dans le format correct Je l'utilise, mais il est très lent:

private bool BitmapFromTexture(FastBitmapSingle fastBitmap, Texture2D texture) 
{ 
    using (MemoryStream ms = new MemoryStream()) 
    { 
     Texture2D.ToStream(device.ImmediateContext, texture, ImageFileFormat.Bmp, ms); 
     ms.Position = 0; 
     using (Bitmap temp1 = (Bitmap)Bitmap.FromStream(ms)) 
     { 
      Rectangle bounds = new Rectangle(0, 0, temp1.Width, temp1.Height); 
      BitmapData BitmapDataIn = temp1.LockBits(bounds, ImageLockMode.ReadWrite, temp1.PixelFormat); 
      using (DataStream dataStreamIn = new DataStream(BitmapDataIn.Scan0, BitmapDataIn.Stride * BitmapDataIn.Height, true, false)) 
      using (DataStream dataStreamOut = new DataStream(fastBitmap.BitmapData.Scan0, fastBitmap.BitmapData.Stride * fastBitmap.BitmapData.Height, false, true)) 
      { 
       dataStreamIn.CopyTo(dataStreamOut); 
      } 
      temp1.UnlockBits(BitmapDataIn); 
      BitmapDataIn = null; 
     } 
    } 
    return true; 
} 

Y at-il un moyen plus rapide ??? J'ai essayé beaucoup, comme ceci:

Mais le DataRectangle a exactement 8 fois plus de données alors je besoin dans mon DataStream:

private bool BitmapFromTexture(FastBitmapSingle fastBitmap, Texture2D texture) 
{ 
    using (Texture2D buff = Helper.CreateTexture2D(device, texture.Description.Width, texture.Description.Height, Format.B8G8R8A8_UNorm, BindFlags.None, ResourceUsage.Staging, CpuAccessFlags.Read | CpuAccessFlags.Write)) 
    { 
     device.ImmediateContext.CopyResource(texture, buff); 

     using (Surface surface = buff.AsSurface()) 
     using (DataStream dataStream = new DataStream(fastBitmap.BitmapData.Scan0, fastBitmap.BitmapData.Stride * fastBitmap.BitmapData.Height, false, true)) 
     { 
      DataRectangle rect = surface.Map(SlimDX.DXGI.MapFlags.Read); 

      rect.Data.CopyTo(dataStream); 

      surface.Unmap(); 
     } 
    } 

    return true; 
} 

peut-elle aider tout le monde s'il vous plaît? La copie de mes données prend environ 50% du temps de calcul total. Si cela pouvait être résolu, mon application serait beaucoup plus rapide ...

Répondre

0

J'ai trouvé une solution grâce à: http://www.rolandk.de/wp/2013/06/inhalt-der-rendertarget-textur-in-ein-bitmap-kopieren/

Mais l'histoire est un peu plus compliqué, car la texture hauteur ne correspond pas à la Stride Bitmap, alors voici ma solution, 10 fois plus rapide que celle de mon question:

private bool BitmapFromTexture(FastBitmapSingle fastBitmap, Texture2D texture, int row, int col) 
{ 
    using (Texture2D stage = Helper.CreateStagingTexture(device, fastBitmap.BitmapWidths[col], fastBitmap.BitmapHeights[row])) 
    { 
     device.ImmediateContext.CopyResource(texture, stage); 
     DataStream dsIn; 
     DataBox dataBox = device.ImmediateContext.MapSubresource(stage, 0, 0, MapMode.Read, D3D.MapFlags.None, out dsIn); 
     int dx = dataBox.RowPitch - fastBitmap.BitmapData[row][col].Stride; 
     try 
     { 
      using (DataStream dsOut = new DataStream(fastBitmap.BitmapData[row][col].Scan0, fastBitmap.BitmapData[row][col].Stride * fastBitmap.BitmapData[row][col].Height, false, true)) 
      { 
       for (int r = 0; r < fastBitmap.BitmapData[row][col].Height; r++) 
       { 
        dsOut.WriteRange<byte>(dsIn.ReadRange<byte>(fastBitmap.BitmapData[row][col].Stride)); 
        dsIn.Position += dx; 
       } 
      } 
     } 
     finally 
     { 
      device.ImmediateContext.UnmapSubresource(stage, 0); 
     } 
     dsIn.Dispose(); 
    } 
    return true; 
} 
0

Le convertisseur J'utilise est ceci:

public static BitmapSource Texture2DToBitmapSource(Texture2D texture2D) 
    { 
     using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream()) 
     { 
      Texture2D.ToStream(App.device.ImmediateContext, texture2D, ImageFileFormat.Png, memoryStream); 
      memoryStream.Seek(0, System.IO.SeekOrigin.Begin); 
      return BitmapFrame.Create(memoryStream, BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.OnLoad); 
     } 
    } 

Cependant, je vais avoir un problème avec le dpi être 72 et non 96 comme le BitmapSource que j'utilise dans mon programme. J'espère que ça aide certains.

Aussi j'utilise SlimDX.

Les conversions de bitmap WPF sont à peu près un casse-tête de son introduction. Obtenir la vitesse maximale en entrant dans du code et des lockbits dangereux nécessitera probablement des conversions de Pbgra et bgra vers rgba, etc. En général, j'ai fini par revenir à l'ancien bitmap de dessin pour me convertir en BitmapSource dans de nombreux programmes. Ce sniplet est ce que j'utilise jusqu'à ce que je puisse obtenir le PixelFormat correct de et vers mes shaders de calcul.

 using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream()) 
     { 
      Texture2D.ToStream(App.device.ImmediateContext, texture, ImageFileFormat.Png, memoryStream); 
      memoryStream.Seek(0, System.IO.SeekOrigin.Begin); 

      //Create an image from a stream. 
      System.Drawing.Image bitmap = System.Drawing.Bitmap.FromStream(memoryStream); memoryStream.Close(); 
      var hBitmap = ((System.Drawing.Bitmap)bitmap).GetHbitmap(); 
      BitmapSource source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
       hBitmap, 
       IntPtr.Zero, 
       Int32Rect.Empty, 
       BitmapSizeOptions.FromEmptyOptions() 
       ); 
      if (!(source.Width == pixelWidth)) { } 
      if (!(source.Height == pixelHeight)) { } 
      return source; 
     } 

utilisant le HBITMAP d'un System.Drawing.Image ou System.Drawing.Bitmap a plus de contrôle sur LockBits et conversions pour les différents format de pixel. Les anciennes fonctions CreateBitmap et les DIB utilisent également HBITMAP pour les conversions.

Un autre goulot d'étranglement dans la vitesse J'imagine être dans la routine Texture2D.ToStream(). Ces ImageFileFormat.Png, ImageFileFormat.Bmp, ImageFileFormat.Jpg etc. SlimDX n'a ​​pas ajouté de fonction de copie dans le Texture2D, et DX11 l'a quelque part.

+0

Afin de préserver PixelFormat et Dpi j'utilise mon Temp Bitmap, puis copiez le PixelData à une image avec le format correct. –