2012-03-06 15 views
1

私はOpenGL ES 1.0とQuartzを使用して書かれた私のペイントアプリケーションを持っています。 私は、より良いパフォーマンスと新機能のためにOpenGL ES 2.0を使って書き直そうとしています。 私は2つのシェーダを書いています.1つはユーザーの入力をテクスチャにレンダリングし、もう1つはいくつかのルールに従ってこのテクスチャを他のテクスチャとミックスします。 突然、私は第二世代のシェーダがiPad 1世代で長すぎることに気付きました - 私は10-15fpsしか持っていません。 iPad 2は60+ fpsで完璧に動作します。私は、元のアプリケーション(OpenGL ES 1.0)が両方のデバイスで正常に動作するので、少しショックを受けました。それは2つのポリゴンだけをレンダリングします(ただしほぼフルスクリーンです)。 精度の変更、いくつかの数学演算のコメント、ハードコーディングされたテクスチャ呼び出しなど、いくつかの最適化を試みました。少し助けましたが、私はまだ60fpsから遠いです。このシェーダの呼び出しに完全にコメントするときだけ、60fpsが得られます。iPad上でのシェーダの低性能第1世代

何か不足していますか?私はOpenGLであまり経験はありませんが、オリジナルのアプリケーションのように、このシェーダは両方の世代のデバイスでうまく動作しなければならないと思います。私の頂点とフラグメントシェーダは以下のとおりです。

===============バーテックスシェーダ===================

uniform mat4 modelViewProjectionMatrix; 

attribute vec3 position; 
attribute vec2 texCoords; 

varying vec2 fTexCoords; 

void main() 

{ 

    fTexCoords = texCoords; 

    vec4 postmp = vec4(position.xyz, 1.0); 
    gl_Position = modelViewProjectionMatrix * postmp; 


} 

===============フラグメントシェーダ===================

 precision highp float; 

     varying lowp vec4 colorVarying; 
     varying highp vec2 fTexCoords; 
     uniform sampler2D texture; // black & white user should paint 
     uniform sampler2D drawingTexture; // texture with user drawings I rendered earlier 
     uniform sampler2D paperTexture; // texture of sheet of paper 
     uniform float currentArea; // which area we should not shadow 
     uniform float isShadowingOn; // bool - should we shadow some areas of picture  

     void main() 
     { 
      // I pass 1024*1024 texture here but I only need 560*800 so I do some calculations to find real texture coordinates 

      vec2 convertedTexCoords = vec2(fTexCoords.x * 560.0/1024.0, fTexCoords.y * 800.0/1024.0); 

      vec4 bgImageColor = texture2D(texture, convertedTexCoords);   
      float area = bgImageColor.a;   
      bgImageColor.a = 1.0;    
      vec4 paperColor = texture2D(paperTexture, convertedTexCoords);  
      vec4 drawingColor = texture2D(drawingTexture, convertedTexCoords); 

    // if special area   
      if (abs(area - 1.0) < 0.0001) {    
       // if shadowing ON   
       if (isShadowingOn == 1.0) {    
        // if color of original image is black   
        if ((bgImageColor.r < 0.1) && (bgImageColor.g < 0.1) && (bgImageColor.b < 0.1)) {   
         gl_FragColor = vec4(bgImageColor.rgb, 1.0) * vec4(0.5, 0.5, 0.5, 1.0);   
        }      
        // if color of original image is grey 

        else if (abs(bgImageColor.r - bgImageColor.g) < 0.15 && abs(bgImageColor.r - bgImageColor.b) < 0.15 && abs(bgImageColor.g - bgImageColor.b) < 0.15 && bgImageColor.r < 0.8 && bgImageColor.g < 0.8 && bgImageColor.b < 0.8){ gl_FragColor = vec4(paperColor.rgb * bgImageColor.rgb * 0.4 - drawingColor.rgb * 0.4, 1.0);} 


       else 
       {  
       gl_FragColor = vec4(bgImageColor.rgb, 1.0) * vec4(0.5, 0.5, 0.5, 1.0);  
        } 
       } 

       // if shadowing is OFF   
       else {   
        // if color of original image is black  
       if ((bgImageColor.r < 0.1) && (bgImageColor.g < 0.1) && (bgImageColor.b < 0.1)) { 
        gl_FragColor = vec4(bgImageColor.rgb, 1.0); 
       } 

        // if color of original image is gray 
       else if (abs(bgImageColor.r - bgImageColor.g) < 0.15 && abs(bgImageColor.r - bgImageColor.b) < 0.15 && abs(bgImageColor.g - bgImageColor.b) < 0.15 
       && bgImageColor.r < 0.8 && bgImageColor.g < 0.8 && bgImageColor.b < 0.8){ 
        gl_FragColor = vec4(paperColor.rgb * bgImageColor.rgb * 0.4 - drawingColor.rgb * 0.4, 1.0); 

        } 

        // rest 
       else { 
        gl_FragColor = vec4(bgImageColor.rgb, 1.0); 
       } 


       } 
      } 

    // if area of fragment is equal to current area 
     else if (abs(area-currentArea/255.0) < 0.0001) { 
      gl_FragColor = vec4(paperColor.rgb * bgImageColor.rgb - drawingColor.rgb, 1.0); 
     } 

    // if area of fragment is NOT equal to current area 
     else { 
      if (isShadowingOn == 1.0) { 
       gl_FragColor = vec4(paperColor.rgb * bgImageColor.rgb - drawingColor.rgb, 1.0) * vec4(0.5, 0.5, 0.5, 1.0);   
      } else { 
       gl_FragColor = vec4(paperColor.rgb * bgImageColor.rgb - drawingColor.rgb, 1.0); 
      } 
     } 
    } 

答えて

0

シェイダーの分岐についてのJustSidの有効な点を超えて、ここで間違ったことがいくつかあります。

PVRUniScoEditor results

の最良のパフォーマンスを示している:私はちょうど(あなたが本当に取得し、their free SDKの一部である必要があります)イマジネーションTexhnologies' PVRUniScoエディタを使用して、このフラグメントシェーダを実行する場合、最初に、私はこれを参照してください42サイクル、最悪のシェーダは52です。 similar case of fragment shader tuning I asked aboutから、11-16サイクルのフラグメントシェーダーがiPad 1(15〜29FPS)でレンダリングするのに35〜68msかかったことがわかりました。あなたはそれを合理的なレンダリング時間にするためには、これをもっと緊密にする必要があります。

ブランチの一部を削除するには、ステップ関数を使用するか、アルファチャンネルでトリックをプレイすることができます。私はこれを行い、シェーダのレンダリング時間を大幅に短縮しました。私はisShadowingOnユニフォームを渡すことはできませんが、これを2つのシェーダに分割して、これをオンとオフの異なるケースで使用します。

分岐以外にも、フラグメントシェーダ内でフェッチするテクスチャ座標を計算した結果、bgImageColorpaperColor、およびdrawingColorの依存テクスチャを実行していることがわかりました。iOSデバイス内のタイルベースの遅延レンダラでは、テクスチャフェッチの特定の最適化が使用されないため、これはひどく高価です。このフラグメントごとに計算するのではなく、この計算を頂点シェーダーに移動し、その結果をフラグメントシェーダーに渡すことをお勧めします。テクスチャをフェッチするために座標として変化するものを使用すると、パフォーマンスが大幅に向上します。

これを調整するために行うことができるより小さなものもあります。例えば、

gl_FragColor = vec4((paperColor.rgb * bgImageColor.rgb - drawingColor.rgb) * 0.4, 1.0); 

は、エディタがあなたのシェーダーを生きる - コンパイルします

gl_FragColor = vec4(paperColor.rgb * bgImageColor.rgb * 0.4 - drawingColor.rgb * 0.4, 1.0); 

よりも若干速くする必要がありますので、あなたは、コード内でこれらの操作を試してみると、推定GPUサイクルの面で結果を見ることができます。

+0

このような詳細な回答ありがとうございます!今私は自分の間違いを理解し、正しい方向性を持っています。 P.P.ところで、Brad、それはあなたがOpenGLを堪能する際に私を刺激したのです。 iTunesのMATCのレッスンをありがとう!すごい仕事! – Seify

2

分岐はです実際にははシェーダで実行するのが高価ですが、GPUがシェーダを並行して実行する可能性がなくなり、断片シェーダ(多くの場合可能な限り速くなるシェーダ)に多くの分岐があります。それ以上に悪いことに、GPU自体で計算された値に基づいて分岐しており、これもあなたのパフォーマンスを大幅に低下させます。

実際にGPUにいくつかの「余分な仕事」をさせるよう、できるだけ多くのブランチを削除してください。テクスチャアトラスを最適化しようとせず、すべてをレンダリングします(これが可能な場合)。これは現在のバージョンよりも高速です。これでうまくいかない場合は、複数の小さなシェーダでシェーダを分割してください。各シェーダは、GPUではなく、より大きなシェーダとブランチの特定の部分だけを分割します(描画呼び出しごとに一度行う必要があります。すべての「ピクセル」ではなく)。

+0

ありがとうございます、私は支店を削除し、何が起こるかを見てみます。 – Seify

+0

これでフル60 fpsに戻ることはできませんが、実際にはそうであると信じています。シェーダで考えることができる他のものがいくつかあります。しかし、彼らは実際に果物をぶら下げているわけではなく、もう少し作業が必要なので、おそらく価値のあるものではありません。 – JustSid

+0

ブランチを削除すると助けになりましたが、フラグメントシェーダから頂点シェーダへのテクスチャ座標の計算を移動したときにほとんどのパフォーマンスが向上しました。 – Seify

関連する問題