在计算复杂度方面优化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();
}
}
答案 0 :(得分:1)
我对HLSL的内部结构并不熟悉,但从我从GLSL学到的东西是:从不分支。它可能会执行这两个部分,然后决定它们的哪个结果应该有效。
据我所知,除编译器本身外没有自动工具。对于非常低级别的优化,您可以使用fxc和/ Fc参数来获取程序集列表。列出了可能的装配说明here。值得一提的一个低级优化是MAD:乘法和加法。这可能没有针对MAD操作进行优化(我不确定,只是自己尝试一下):
a *= b;
a += c;
但这应该针对MAD进行优化:
a = (a * b) + c;
答案 1 :(得分: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编译器在poperties中有一个选项来启用Optimizations。但是你可以做的最好的优化是尽可能简单地编写HLSL代码并使用内在函数http://msdn.microsoft.com/en-us/library/windows/desktop/ff471376(v=vs.85).aspx
这些函数类似于C的memcpy
,使用正文中的汇编代码,使用系统资源,如128位寄存器(是的,CPU具有128位寄存器http://en.wikipedia.org/wiki/Streaming_SIMD_Extensions)和强大的快速操作。