2016-11-27 18 views
2

次の設定を検討してください:ディスク上にいくつかの画像があります。それらの画像は別のプロジェクトに属するので変更できません。私はちょうどそれらを読んだ。WPFアプリケーションではいつPixelFormats.Pbgra32を使用しますか?

私のアプリで最適に見えるように処理が必要です。つまり、ピクセルシェーダが処理されたことを意味します。 処理が終了すると、出力イメージはListViewや他のコントロールのサムネイルとして使用されます。

ピクセルシェーダーを作成するのはかなり簡単なので、出力形式としてPixelFormats.Bgra32を選択しました。 しかし、私はPixelFormats.Pbgra32をWindowsでネイティブに使用していますので、高速です。

フェード効果が画像に使用されている場合、まだ高速ですか?これをフレームワークに残すのではなく、管理されたコードでチャネルをあらかじめ乗算することは意味がありますか?

+1

モニターにはアルファチャンネルがありません。したがって、多重乗算が必要ないため、事前に乗算されたピクセル形式が高速になります。しかし、フェーディング効果を実装するシェーダは、元のRGB値を回復して新しいアルファを再適用するためにはるかに多くの作業をしなければなりません。精度の大幅な低下。それがより良いと想像するのは難しいです、それを試してみてください。 –

+0

私はあなたが正しいと思いますが、「Pbgra32を使う」ことが何度も見られました。しかし、ビットマップが直接レンダリングされているとすれば、最適化されていると思います。WPFがすべてのレンダリングをそれらを合成するレンダリングキューに送信すれば、どのように直接レンダリングできますか?すべてのWPFコントロールは32ビットのカラーブラシを使用しますが、ブラシのアルファバイトが0xffであれば、レンダラはステップをスキップすることもできます。 – Harry

答えて

1

だから私は、私は(/危険なでコンパイルする)可能性がどのようにそれをテストした:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Threading; 

namespace BgraVsPbgra { 

    public partial class MainWindow : Window { 

     readonly WrapPanel Panel; 
     readonly TextBlock Output; 
     readonly PixelFormat FN = PixelFormats.Bgra32; 
     readonly PixelFormat FP = PixelFormats.Pbgra32; 
     readonly List<long> TN = new List<long>(); 
     readonly List<long> TP = new List<long>(); 
     DateTime T0; 
     long DT => (DateTime.Now - T0).Ticks; 
     DateTime Now => DateTime.Now; 

     public MainWindow() { 
      InitializeComponent(); 
      SizeToContent = SizeToContent.WidthAndHeight; 
      Title = "Bgra32 vs Pbgra Benchmark"; 
      Panel = new WrapPanel { 
       Width = 512, 
       Height = 512 
      }; 
      Output = new TextBlock { 
       HorizontalAlignment = HorizontalAlignment.Center, 
       VerticalAlignment = VerticalAlignment.Center, 
       Foreground = new SolidColorBrush(Colors.White) 
      }; 
      (Content as Grid).Children.Add(Panel); 
      (Content as Grid).Children.Add(Output); 
      Dispatcher.BeginInvoke(new Action(() => Start()), DispatcherPriority.SystemIdle); 
     } 

     private async void Start() { 
      Output.Text += "Bgra32 vs Pbgra32 benchmark started.\r\n\r\n"; 
      var t0 = DateTime.Now; 
      var n = 3; 
      var i = 16384; 
      for (var p = 1; p <= n; p++) { 
       Output.Text += $"\r\nPass {p}/{n}.\r\n\r\n"; 
       await Benchmark(i/4, 0.75, true); 
       await Benchmark(i/4, 0.75, false); 
       await Benchmark(i/4, 1, true); 
       await Benchmark(i/4, 1, false); 
      } 
      var t = (DateTime.Now - t0).TotalSeconds; 
      Output.Text += $"\r\nDone in {t:0.0}s.\r\n"; 
     } 

     private async Task Benchmark(int n = 256, double opacity = 1, bool cheat = false) { 
      Output.Text += $"Benchmarking with opacity = {opacity}... "; 
      if (cheat) Output.Text += "CHEATING!... "; 
      //Output.Text += "\r\n"; 
      for (int i = 0; i < n; i++) await Dispatcher.BeginInvoke(new Action(async() => await DrawTestAsync(opacity, cheat)), DispatcherPriority.Send); 
      Output.Text += ($"Pbgra32 advantage: {(TN.Average()/TP.Average() * 100d - 100d):0.0}%\r\n"); 
     } 

     async Task DrawTestAsync(double opacity = 1, bool cheat = false) { 
      await Dispatcher.BeginInvoke(new Action(() => { 
       Panel.Children.Clear(); 
       for (int i = 0; i < 8; i++) { 
        T0 = Now; Panel.Children.Add(new Image { Source = CreateBitmap(FP, cheat), Width = 128, Height = 128, Opacity = opacity }); TP.Add(DT); 
        T0 = Now; Panel.Children.Add(new Image { Source = CreateBitmap(FN, cheat), Width = 128, Height = 128, Opacity = opacity }); TN.Add(DT); 
       } 
      }), DispatcherPriority.Send); 

     } 



     BitmapSource CreateBitmap(PixelFormat pixelFormat, bool cheat = false) { 
      var bitmap = new WriteableBitmap(256, 256, 96, 96, pixelFormat, null); 
      bitmap.Lock(); 
      unsafe 
      { 
       var pixels = (uint*)bitmap.BackBuffer; 
       if (pixelFormat == FN || cheat) 
        for (uint y = 0; y < 256; y++) for (uint x = 0; x < 256; x++) pixels[x + y * 256] = 0x80000000u | (x << 16) | y; 
       else 
        for (uint y = 0; y < 256; y++) for (uint x = 0; x < 256; x++) pixels[x + y * 256] = 0x80000000u | (x/2 << 16) | y/2; 
      } 
      bitmap.Unlock(); 
      bitmap.Freeze(); 
      return bitmap; 
     } 

    } 

} 

私はかなりランダムな結果を得るが、Pbgra32ピクセル形式を使用して、時間のほとんどは少し(3%のような)のようですBgra32ピクセル形式を使用するよりも高速です。

Pbgra32フォーマットを使用する場合は、チャネルごとにいくつかの追加操作を行う必要がありますが、2つの追加のディビジョンは測定可能な差がないようです。だから、

あなたがより速く、3%ごろ、あなたのビットマップを作りたい場合は、同じくらい醜い見えるかもしれませんPbgra32形式とpr = r * a/255などのプリマルチプライのチャンネルを使用します。

uint pixel = a << 24 | r * a/255 << 16 | g * a/255 << 8 | b * a/255; 

そしてpixel機能を作る、またはあなたは殺してはいけませんのパフォーマンス。パフォーマンスといえば、安全でないピクセル操作は、安全なCopyPixels()/WritePixels()メソッドを使用する場合よりも2倍から3倍速いようです。

Nahでは、ビットマップ用のビットマップまたはピクセルシェーダーの作成にはPbgra32を使用しません。私の意見は:価値がない。私が間違っているなら私を訂正してください。

関連する問題