【问题标题】:DirectX 11 Compute Shader - not writing all valuesDirectX 11 Compute Shader - 不写入所有值
【发布时间】:2010-12-18 20:22:04
【问题描述】:

我正在尝试使用 DirectX11 计算着色器进行分形渲染的一些实验。 提供的示例在 FeatureLevel_10 设备上运行。

我的 RwStructured 输出缓冲区的数据格式为 R32G32B32A32_FLOAT

问题是,当写入缓冲区时,似乎只有 ALPHA ( w ) 值被写入其他内容...... 这是着色器代码:

struct BufType
{
    float4 value;
};

cbuffer ScreenConstants : register(b0)
{
  float2 ScreenDimensions;
  float2 Padding;
};

RWStructuredBuffer<BufType> BufferOut : register(u0);

[numthreads(1, 1, 1)]
void Main( uint3 DTid : SV_DispatchThreadID )
{
    uint index = DTid.y * ScreenDimensions.x + DTid.x;
    
    float minRe = -2.0f;
    float maxRe = 1.0f;
    float minIm = -1.2;
    float maxIm = minIm + ( maxRe - minRe ) * ScreenDimensions.y / ScreenDimensions.x;
    float reFactor = (maxRe - minRe ) / (ScreenDimensions.x - 1.0f);
    float imFactor = (maxIm - minIm ) / (ScreenDimensions.y - 1.0f);
    float cim = maxIm - DTid.y * imFactor;
    
    uint maxIterations = 30;
    
    float cre = minRe + DTid.x * reFactor;
    float zre = cre;
    float zim = cim;
    
    bool isInside = true;
    uint iterationsRun = 0;
    
    for( uint n = 0; n < maxIterations; ++n )
    {
        float zre2 = zre * zre;
        float zim2 = zim * zim;
        
        if ( zre2 + zim2 > 4.0f )
        {
            isInside = false;
            iterationsRun = n;
        }
        
        zim = 2 * zre * zim + cim;
        zre = zre2 - zim2 + cre;
    }
    
    if ( isInside )
    { 
        BufferOut[index].value = float4(1.0f,0.0f,0.0f,1.0f);
    }
}

代码实际上在某种意义上产生了正确的结果(2D Mandelbrot 集),但似乎不知何故只触及了 alpha 值,没有写入任何其他内容,尽管集内的像素应该是红色的......(图像是黑白的)

有人知道这里发生了什么吗?

【问题讨论】:

  • 您只显示了生成缓冲区的 HLSL 代码。实际渲染缓冲区的 c 代码呢?你怎么确定你的缓冲区没有红色成分?
  • 您是否检查了生成的 Asm Shader 是否存在潜在的编译器错误?

标签: directx-11 compute-shader


【解决方案1】:

经过一番摆弄后,我发现了问题。 我没有从 MS 中找到任何提到这一点的文档,所以它也可能是 Nvidia 特定的驱动程序问题。

显然,您只能在每次计算着色器调用时将 ONCE 写入 RWSructuredBuffer 中的同一元素。而且你还必须写一次。

我更改了代码以在局部变量中累积正确的颜色,现在只在着色器末尾编写一次。

现在一切都以这种方式完美运行。

【讨论】:

  • 无论如何写一次 BufferOut 是有意义的(性能方面的原因),因为 RWStructuredBuffer 应该驻留在视频内存中。局部变量驻留在 GPU 芯片以及 TGSM 上。
【解决方案2】:

我不确定,但不应该是 BufferOut decl:

RWStructuredBuffer<BufType> BufferOut : register(u0);

而不是:

RWStructuredBuffer BufferOut : register(u0);

如果您只使用 float4 写入目标,为什么不直接使用:

RWBuffer<float4> BufferOut : register (u0);

也许这会有所帮助。

【讨论】:

  • 你是绝对正确的,不幸的是这只是我这边的一个复制过去的错误。原始声明当然是 RWStructedBuffer BufferOut : register(u0)
【解决方案3】:

今天又玩了一遍,我又遇到了同样的问题。 以下代码产生全白输出:

[numthreads(1, 1, 1)]
void Main( uint3 dispatchId : SV_DispatchThreadID )
{
    float4 color = float4(1.0f,0.0f,0.0f,1.0f);
    WriteResult(dispatchId,color);
}

WriteResult 方法是我的 hlsl 标准库中的实用方法。

长话短说。在我从驱动程序版本 192 升级到 195(beta) 后,问题就消失了。 似乎驱动程序在计算着色器支持方面存在一些明确的问题,所以要小心。

【讨论】:

  • 几周前我也编写了自己的 WriteResult 函数。它适用于 refrast(功能级别 5_0),由于我无法访问 DX11 类 GPU,因此未在硬件上进行测试。 Refrast 绝对值得用于解决此类问题。
【解决方案4】:

从我所见,计算机着色器仅在您需要比传统像素着色器更通用的计算模型时有用,或者如果您可以加载数据然后在快速共享内存中的线程之间共享它。我相当肯定你会为 mandelbrot 着色器使用像素着色器获得更好的性能。

在我的设置(win7,feb 10 dx sdk,gtx480)上,我的计算着色器的设置时间超过 0.2-0.3 毫秒(绑定 SRV 和 UAV,然后调用 dispatch())。

如果您进行 PS 实施,请发表您的经验。

【讨论】:

    【解决方案5】:

    我没有直接使用 DX 计算着色器的经验,但是...

    为什么要设置 alpha = 1.0?

    IIRC,这使像素 100% 透明,因此您的内部像素是透明的红色,并显示为在它们后面绘制的任何颜色。 当 alpha = 1.0 时,从不使用 RGB 分量。

    【讨论】:

      猜你喜欢
      • 2015-06-17
      • 2015-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多