2011-02-10 24 views
3

数時間のデバッグと分析の結果、私は最終的に競合状態の原因を切り分けることができました。それを解決することは別の問題です!Java AWT drawImage競合条件 - 同期を使用して回避する方法

動作中の競合状態を確認するために、何らかの方法でデバッグプロセスにビデオを記録しました。それ以来私はその状況を理解していたので、デバッギングプロセスの一環として実装された貧弱な解説と愚かなメカニズムを許してください。だから、

http://screencast.com/t/aTAk1NOVanjR

、状況:我々は、レンダリングプロセスを(起動、ダブルバッファリング表面の実装、本質的に連続してループする継続的なスレッドがある(すなわちするjava.awt.Frameまたはウィンドウ)を持っていますUIレイアウトを実行してバックバッファにレンダリングします)、レンダリング後の領域をバックバッファからスクリーンにブリットします。 - それにも実装(AWT.javaでライン507、

public RenderedRegions render() { 
    // pseudo code 
    RenderedRegions r = super.render(); 
    if (r==null) // nothing rendered 
     return 
    for (region in r) 
     establish max bounds 
    blit(max bounds) 
    return r; 
} 

任意AWT表面実装と同じように:ここ

レンダリングダブルバッファの擬似コードのバージョン(フルバージョン線Surface.javaの824)ですリンク制限:( - また、画面にバックバッファからブリット塗料/更新オーバーライド)PLAT/AWT.javaとコア/ Surface.javaを交換し、Surface.javaリンクを使用:

 public void paint(Graphics gr) { 
      Rectangle r = gr.getClipBounds(); 
      refreshFromBackbuffer(r.x - leftInset, r.y - topInset, r.width, r.height); 
     } 

ブリットが実装されています( AWT.javaでライン371)のdrawImage()関数で使用する:ここでの問題は、drawImageメソッドは非同期とそのAであることのようです、私は仮定を作り始めるところ、これがある)

/** synchronized as otherwise it is possible to blit before images have been rendered to the backbuffer */ 
    public synchronized void blit(PixelBuffer s, int sx, int sy, int dx, int dy, int dx2, int dy2) { 
     discoverInsets(); 
     try { 
      window.getGraphics().drawImage(((AWTPixelBuffer)s).i, 
           dx + leftInset, dy + topInset,  // destination topleft corner 
           dx2 + leftInset, dy2 + topInset, // destination bottomright corner 
           sx, sy,       // source topleft corner 
           sx + (dx2 - dx), sy + (dy2 - dy), // source bottomright corner 
           null); 
     } catch (NullPointerException npe) { /* FIXME: handle this gracefully */ } 
    } 

(警告! paint/updateを介してrefreshBuffer()からblitが呼び出されますが、最初にが呼び出され、秒が発生します。

だから... blitはすでに同期されています。競合状態を防止する明白な方法は機能しません。

これまでのところ私は2つの解決策が出ているが、それらのどちらが理想的です:(:次のレンダーパス
両論の

  1. 再ブリット:パフォーマンスヒット、まだは少しを取得しますちらつき競合状態が発生した(有効画面 - >無効画面 - >有効画面)

  2. は、ペイント/更新にブリットの代わりに設定されたリフレッシュ境界と次のパスに
    短所をレンダリングする上で、それらの境界を使用しないでください。黒を取得画面が無効になったときに点滅します。メインアプリケーションのスレッドが追いついている

ここで(1)は2つの悪のうち小さいものと思われます。 編集:と(2)は動作しません、空白の画面を取得する...(1)うまく動作しますが、まだそこに潜在的に存在する問題をマスクしています。

私が望んでいて、同期の弱い理解とそれの使い方のために思い描くことができないように見えるのは、drawImage()の非同期性を何とか説明するロック機構です。

ImageObserverを使用しますか?

レンダスレッドはペイント/アップデートの外になければならないことに注意してください(Vexi、関心のある人はウェブサイトが古く、ハイパーリンクは2つしか使用できません)。シングルスレッドスクリプトモデルとレイアウトプロセス(レンダリングのサブプロセス)は、スクリプトを呼び出します。

答えて

0

アップデート:ここ良いアプローチ:ここAWT custom rendering - capture smooth resizes and eliminate resize flicker


答えはすべて、すなわちしかプログラムスレッドでバックバッファからリフレッシュpaint()スレッドから、ブリット削除することでした。これはJochen Bedersdorferの答えとは逆ですが、プログラムにはレンダリングを駆動するレイアウトモデルと統合された独自のスクリプトモデルがあるため、彼の答えは決してうまくいきませんでした。

(推測)いくつかの問題は、Direct3D + Javaの不一致であったBufferStrategyを使用するように調整したときに、アクセラレーションされたグラフィックスチップセットを搭載したJavaの複数モニタのサポートが劣っていることに起因します。

本質的にpaint()update()は、ブロッキングコールに軽減されます。これははるかに良く機能しますが、1つの欠点があります。滑らかなサイズ変更はありません。

private class InnerFrame extends Frame() { 
    public void update(Graphics g) { } 
    public void paint(Graphics g) { } 
    .... 
} 

私は画像にレンダリングされるように非効率的であるように私には思えるように私はこのアプローチに満足して100%ではないですが、バッファの戦略を使用して終了し、その後するBufferStrategyに完全な画像をコピーし、画面にshow()を実行します。

また、私はSwingベースの代替案を実装しましたが、私は特にそれを好まないのです。これはImageIconでJLabelを使用し、プログラムスレッド(EDTではなく)がImageIconでラップされたImageを描画します。

これ以上の目的でこれを調べる時間があるときには私に質問することができますが、今は2つの実装があり、私はそれらを発見する気楽なたくさんを学んだ。

0

わかりませんが、AWTペイントスレッドでBlitを実行するとどうなりますか?

+0

「何が起こったのか」を意味すると思いますが、問題はまだ発生します。 blitコードをpaintメソッドにコピーしようとしましたが、同じように動作します。 (FWIWはpaintが既にrefreshFromBackBufferを使って間接的にblitと呼んでいたため実際の違いはありませんでしたが、徹底的に私が提案したことを試してみました) –

+0

drawImageは無茶です。コードがAWTイベントハンドラスレッド(つまりペイントスレッド)で呼び出されない場合にのみ、非同期になります。そしてpaintが間接的にBlitを呼び出すとGraphicsオブジェクトを渡す必要があります –

+0

私はdrawImageが非同期であると仮定しています(確かに状況によってはありますが、すべてではありませんか? paint()を変更してグラフィックスオブジェクトを渡し、どのような影響があるかを確認します。 blitは、メインのアプリケーションスレッドとペイントスレッドの2つのスレッドで発生しています。別の前提として、私は問題を正しく診断しています。私は間違っている可能性があり、私のポストはstackoverflow答えを得るためには少なく、2つの別々のスレッドからのblittingを適切に管理する方法を理解するために多くを得ました。 –

関連する問題