2013-12-07 63 views
0

我有这段代码片段(用于立方体贴图PCF过滤)。我想优化它为着色器模型2.我试图消除存储在制服中的排列矩阵的分支,但它需要太多(2x24)。着色器代码优化

float3 l = normalize(ldir); 
float3 al = abs(l); 
float3 off2, off3, off4; 

if(al.x < al.y) 
{ 
    if(al.y < al.z) 
    { 
     // z is dominant 
     off2 = CubeOffset(l.zxy, float2(0, 1), texelsize).yzx; 
     off3 = CubeOffset(l.zxy, float2(1, 0), texelsize).yzx; 
     off4 = CubeOffset(l.zxy, float2(1, 1), texelsize).yzx; 
    } 
    else 
    { 
     // y is dominant 
     off2 = CubeOffset(l.yxz, float2(0, 1), texelsize).yxz; 
     off3 = CubeOffset(l.yxz, float2(1, 0), texelsize).yxz; 
     off4 = CubeOffset(l.yxz, float2(1, 1), texelsize).yxz; 
    } 
} 
else 
{ 
    if(al.x < al.z) 
    { 
     // z is dominant 
     off2 = CubeOffset(l.zxy, float2(0, 1), texelsize).yzx; 
     off3 = CubeOffset(l.zxy, float2(1, 0), texelsize).yzx; 
     off4 = CubeOffset(l.zxy, float2(1, 1), texelsize).yzx; 
    } 
    else 
    { 
     // x is dominant 
     off2 = CubeOffset(l, float2(0, 1), texelsize); 
     off3 = CubeOffset(l, float2(1, 0), texelsize); 
     off4 = CubeOffset(l, float2(1, 1), texelsize); 
    } 
} 

也许的数学关系可在比较(al.xyy < al.yzz)和碎冰鸡尾酒之间找到。

UPDATE:定义cubeoffset

float3 CubeOffset(float3 swiz, float2 off, float2 texelsize) 
{ 
    float3 ret; 

    ret.yz = swiz.yz + 2.0f * off * texelsize; 
    ret.x = sqrt(1.0f - dot(ret.yz, ret.yz)); 

    if(swiz.x < 0) 
     ret.x *= -1.0f; 

    return ret; 
} 

和编译SM 2.0当HLSL错误:

error X5608: Compiled shader code uses too many arithmetic instruction slots (107). 
Max. allowed by the target (ps_2_0) is 64. 

error X5609: Compiled shader code uses too many instruction slots (111). 
Max. allowed by the target (ps_2_0) is 96. 

GLSL处理它的罚款。目标是向后兼容。

(顺便说一句,该算法是错误的,但是这不是一个问题,现在)

+0

请提供'CubeOffset()'定义 – Drop

+0

加入;我想(可能)预先将其计算为纹理 – Asylum

+0

顺便说一下,您的优化目标是什么?你不适合指令限制?多少钱? – Drop

回答

0

尽管我不知道SM 2.0是否可以解决这个问题,但考虑到GPU功耗的提升,我提供了一个SM 3.0解决方案。

请记住,此代码是从我自己的着色器语言的一个片段(但类似HLSL):

template <int samples> 
float PCFIrregularCUBE(sampler shadowmap, sampler noisetex, float3 ldir, float2 sloc, float2 texelsize) 
{ 
    const float kernelradius = 2.0f; 

    float3 l  = normalize(ldir); 
    float3 al = abs(l); 
    float2 noise; 
    float2 rotated; 

    float sd, t, s; 
    float d = length(ldir); 

    noise = tex2D(noisetex, sloc); 
    noise = normalize(noise * 2.0f - 1.0f); 

    float2 rotmat0 = float2(noise.x, noise.y); 
    float2 rotmat1 = float2(-noise.y, noise.x); 
    float3 off; 

    s = 0; 

    for(int i = 0; i < samples; ++i) { 
     rotated.x = dot(irreg_kernel[i], rotmat0) * kernelradius; 
     rotated.y = dot(irreg_kernel[i], rotmat1) * kernelradius; 

     if(al.x < al.y) { 
      if(al.y < al.z) 
       off = CubeOffsetZXY(l, rotated, texelsize); 
      else 
       off = CubeOffsetYXZ(l, rotated, texelsize); 
     } else { 
      if(al.x < al.z) 
       off = CubeOffsetZXY(l, rotated, texelsize); 
      else 
       off = CubeOffsetXYZ(l, rotated, texelsize); 
     } 

     sd = texCUBE(shadowmap, off).r; 

     t = ((d > sd) ? 0.0f : 1.0f); 
     s += ((sd < 0.001f) ? 1.0f : t); 
    } 

    return s * (1.0f/samples); 
} 

随着CubeOffsetXXX是这样的:

float3 CubeOffsetZXY(float3 swiz, float2 off, float2 texelsize) 
{ 
    float3 ret; 

    ret.xy = swiz.xy + 2.0f * off * texelsize * swiz.z; 
    ret.z = sqrt(1.0f - dot(ret.xy, ret.xy)); 

    if(swiz.z < 0) 
     ret.z *= -1.0f; 

    return ret; 
} 

有关详情,请应为谷歌不规则PCF。在最坏的情况的结果(如在“照相机靠近”)是:

cubemap irregular PCF shadow

通知“盐和胡椒”噪声引起的不规则PCF。从远处看,它是完全可以接受的(孤岛危机1方法)。

0

不是一个真正的优化,但考虑到进行测试。

显然,并非总是需要,在这种情况下,很少有最佳解决方案是移至CPU不适合的额外代码(例如由于指令计数)。在分支的情况下,您可以:

  • 移动分支条件检查CPU
  • 分裂,并移动到不同的着色器分支机构
  • 绑定的条件检查的结果适当的着色器

这是一个最简单的事情你可以做。而且不需要在汇编程序中四处闲逛。问题在于你的条件是在着色器内计算的。

希望它以某种方式帮助。

+0

条件是在着色器内部,所以我不能将它移动到CPU(ldir = wpos - lightpos) – Asylum