1

HLSL シェーダー コードを計算の複雑さ (つまり、シェーダーの実行時間の最小化) の観点から最適化するための成功する戦略は何ですか?

1 つの方法は、シェーダーをコンパイルした結果生じる算術演算の数を最小限に抑えることだと思います。

これは、a) 手動で、b) 自動ツール (存在する場合) を使用してどのように行うことができますか?

手技集(更新)

  • 分岐を避ける (しかし、どのように行うのが最善でしょうか?)
  • 可能な限り: 外部シェーダーを事前計算し、引数として渡します。

コード例は次のとおりです。

float2 DisplacementScroll;

// Parameter that limit the water effect
float glowHeight;
float limitTop;
float limitTopWater; 
float limitLeft;
float limitRight;
float limitBottom;

sampler TextureSampler : register(s0); // Original color
sampler DisplacementSampler : register(s1); // Displacement

float fadeoutWidth = 0.05;

// External rumble displacement
int enableRumble;
float displacementX;
float displacementY;

float screenZoom;

float4 main(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{

// Calculate minimal distance to next border
float dx = min(texCoord.x - limitLeft, limitRight - texCoord.x);
float dy = min(texCoord.y - limitTop, limitBottom - texCoord.y);

///////////////////////////////////////////////////////////////////////////////////////
// RUMBLE                                                        //////////////////////
///////////////////////////////////////////////////////////////////////////////////////

    if (enableRumble!=0)
    {
    // Limit rumble strength by distance to HLSL-active region (think map)
    // The factor of 100 is chosen by hand and controls slope with which dimfactor goes to 1
    float dimfactor = clamp(100.0f * min(dx, dy), 0, 1); // Maximum is 1.0 (do not amplify)

    // Shift texture coordinates by rumble
    texCoord.x += displacementX * dimfactor * screenZoom;
    texCoord.y += displacementY * dimfactor * screenZoom;
    }

//////////////////////////////////////////////////////////////////////////////////////////
// Water refraction (optical distortion) and water like-color tint  //////////////////////
//////////////////////////////////////////////////////////////////////////////////////////

if (dx >= 0)
{
float dyWater = min(texCoord.y - limitTopWater, limitBottom - texCoord.y);

  if (dyWater >= 0)
  {
    // Look up the amount of displacement from texture
    float2 displacement = tex2D(DisplacementSampler, DisplacementScroll + texCoord / 3);

    float finalFactor = min(dx,dyWater) / fadeoutWidth;
    if (finalFactor > 1) finalFactor = 1;

    // Apply displacement by water refraction
    texCoord.x += (displacement.x * 0.2 - 0.15) * finalFactor * 0.15 * screenZoom; // Why these strange numbers ?
    texCoord.y += (displacement.y * 0.2 - 0.15) * finalFactor * 0.15 * screenZoom;

    // Look up the texture color of the original underwater pixel.
    color = tex2D(TextureSampler, texCoord);

    // Additional color transformation (blue shift)
    color.r = color.r - 0.1f;
    color.g = color.g - 0.1f;
    color.b = color.b + 0.3f;

  }
  else if (dyWater > -glowHeight)
  {
   // No water distortion...
   color = tex2D(TextureSampler, texCoord);

   // Scales from 0 (upper glow limit) ... 1 (near water surface)
   float glowFactor = 1 - (dyWater / -glowHeight); 

   // ... but bluish glow
   // Additional color transformation
   color.r = color.r - (glowFactor * 0.1); // 24 = 1/(30f/720f); // Prelim: depends on screen resolution, must fit to value in HLSL Update
   color.g = color.g - (glowFactor * 0.1);
   color.b = color.b + (glowFactor * 0.3);
  }
  else
  {
  // Return original color (no water distortion above and below)
  color = tex2D(TextureSampler, texCoord);
  }
}
else
{
// Return original color (no water distortion left or right)
color = tex2D(TextureSampler, texCoord);
}

   return color;
}

technique Refraction
{
    pass Pass0
    {
        PixelShader = compile ps_2_0 main();
    }
}
4

2 に答える 2

1

操作関数を含む数学的手法を使用してコードを最適化できます。次のようになります。

// Shift texture coordinates by rumble
texCoord.x += displacementX * dimfactor * screenZoom;
texCoord.y += displacementY * dimfactor * screenZoom;

ここでは 3 つの値を乗算しますが、そのうち 1 つだけが GPU のレジスタから取得され、他の 2 つは定数です。事前に乗算してグローバル定数に格納できます。

// Shift texture coordinates by rumble
texCoord.x += dimfactor * pre_zoom_dispx; // displacementX * screenZoom
texCoord.y += dimfactor * pre_zoom_dispy; // displacementY * screenZoom

もう一つの例:

// Apply displacement by water refraction
texCoord.x += (displacement.x * 0.2 - 0.15) * finalFactor * 0.15 * screenZoom; // Why     these strange numbers ?
texCoord.y += (displacement.y * 0.2 - 0.15) * finalFactor * 0.15 * screenZoom;

 0.15 * screenZoom <- can be optimized by one global.

Visual Studio 2012 の HLSL コンパイラには、最適化を有効にするオプションがあります。しかし、可能な最適化は、HLSL コードをできるだけ単純に記述し、組み込み関数http://msdn.microsoft.com/en-us/library/windows/desktop/ff471376(v=vs.85) を使用することです。 aspx これらの関数はmemcpyC のようなもので、128 ビット レジスタ (はい、CPU には 128 ビット レジスタがありますhttp://en.wikipedia.org/wiki/Streaming_SIMD_Extensions ) のようなシステムのリソースを使用する本体でアセンブリ コードを使用し、非常に高速な操作を行います。 .

于 2013-01-21T14:12:50.537 に答える
1

私は HLSL の内部構造にあまり詳しくありませんが、GLSL から学んだことから、何かを分岐してはいけません。おそらく両方の部分を実行してから、どちらの結果が有効かを判断します。

thisthisも見てください。

私の知る限り、コンパイラー以外に自動ツールはありません。非常に低レベルの最適化では、 fxcを /Fc パラメーターと共に使用して、アセンブリ リストを取得できます。考えられる組み立て手順は、ここにリストされています。言及する価値のある低レベルの最適化の 1 つは、MAD (乗算と加算) です。これは MAD 操作に最適化されていない可能性があります (よくわかりません。自分で試してみてください)。

a *= b;
a += c;

ただし、これは MAD に最適化する必要があります。

a = (a * b) + c;
于 2013-01-20T18:53:12.840 に答える