1

在计算复杂度方面优化 HLSL 着色器代码的成功策略是什么(意思是:最小化着色器的运行时间)?

我想一种方法是最小化编译着色器产生的算术运算的数量。

如何做到这一点 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;

这里你将三个值相乘,但其中只有一个来自GPU的寄存器,另外两个是常量,你可以预先相乘并存储在一个全局常量中。

// 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 中学到的是:永远不要分支。它可能会执行这两个部分,然后决定它们的哪个结果应该是有效的。

也看看这个这个

据我所知,除了编译器本身,没有自动工具。对于非常低级别的优化,您可以使用带有 /Fc 参数的fxc来获取程序集列表。此处列出了可能的组装说明。一个值得一提的低级优化是 MAD:乘法和加法。这可能没有针对 MAD 操作进行优化(我不确定,自己尝试一下):

a *= b;
a += c;

但这应该优化为MAD:

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