经常写入片段时出现奇怪的内核工件

时间:2017-12-25 20:26:00

标签: opengl glsl shader artifacts

我正在开发游戏引擎并处理延迟渲染管道。完成(第二遍)(着色)着色器后,我开始在我拥有的其他各种计算机上测试管道。有趣的是,在我的旧笔记本电脑上,我在每个4x8像素组上得到了这种奇怪的伪像(下面的示例)。它看起来像着色器正在执行并最终返回正确的颜色,但是以一种非常随机的方式。

此问题不是错误报告或解决方案请求。我用下面的代码修补程序解决了这个问题。这个主题是为了更好地理解为什么会发生这种情况,并为可能受同一问题影响的其他人提供见解。

Resulting image with artifacts 更详细地描述效果:
大约50%的屏幕具有4x8像素组,这些像素高度调整实际产生的颜色 这些4x8组在每个帧的屏幕上随机放置,导致静态"效果。
某些型号着色不同。如下所示,反光兔子呈蓝色,但折射球呈黄色。这似乎不是Gbuffer问题,因为它们都是从我确定正确的相同纹理中采样(因为我可以在屏幕上同时看到它)。
不同对象的4x8块具有更高的显示正确颜色的速率。你可以看到屈光兔子大多是正确的,但反光地板和折射球只是白色和黄色 根据GPU上运行的其他程序,4x8块的色调会发生巨大变化。

图片应如下所示: Correct render

破碎着色器的伪代码类似于

out vec3 FragColor; // Out pixel of fragment shader

void main() {
    for (int i=0; i<NumberOfPointLights; i++) {
        ... Lighting calculation code...
        FragColor += lighting;
    }

    for (int i=0; i<NumberOfSpotLights; i++) {
        ... Lighting calculation code...
        FragColor += lighting;
    }

    for (int i=0; i<NumberOfDirectionalLights; i++) {
        ... Lighting calculation code...
        FragColor += lighting;
    }
}

为了解决这个问题,我只是简单地初始化了一个临时变量来保存输出颜色,在光照计算过程中将其写入,然后将其写入最后的片段输出。如下:

out vec3 FragColor; // Out pixel of fragment shader

void main() {
    vec3 outcolor = vec3(0);
    for (int i=0; i<NumberOfPointLights; i++) {
        ... Lighting calculation code...
        outcolor += lighting;
    }

    for (int i=0; i<NumberOfSpotLights; i++) {
        ... Lighting calculation code...
        outcolor += lighting;
    }

    for (int i=0; i<NumberOfDirectionalLights; i++) {
        ... Lighting calculation code...
        outcolor += lighting;
    }

    FragColor = outcolor;
}

我感到很惊讶,因为我认为默认情况下会采用此行为。对片段输出的写入实际上并不是每次都写入VRAM,而只是在最后。我的印象是在着色器执行后读取片段输出变量,因此它的全局。

怀疑和疑问

  1. 根据我的研究,我读到4x8像素组的大小是一个&#34;工作组&#34;或&#34;核心&#34;在AMD使用8x8像素工作组的nVidia GPU(我正在使用)上。所以有些事情导致了随机的工作组。输出颜色将永久受影响,直到它被重新分配到屏幕上的其他位置。
  2. 颜色根据使用GPU的其他因素而变化的事实告诉我,GPU具有非常复杂的内存分配方案,并且它可以从其他程序中读取。内存(我怀疑)或着色器每帧都获得未初始化的内存。但是每次都会写出相同的纹理内存吗?
  3. 写入片段输出变量每次写入VRAM,每个工作组写入太多次会导致工作组保释,留下混合结果。这可以解释为什么临时/局部变量有效。
  4. 因为我总是使用+ =(读然后写)临时变量初始化作为一个明确的指令,以黑色开始并添加到它,而直接写入片段直接添加到该像素的最后一种颜色。如果这种情况虽然如此,为什么它在高端PC上正常工作?
  5. 其他详情

    我的旧笔记本电脑使用带有Optimus技术的GT540m,集成了Intel 3000显卡(这里没有使用) 我的新台式电脑使用的是GTX1070。 在运行应用程序期间,两个GPU都使用非常少的VRAM,小于100MB。 正在使用#version 400 core

    编译着色器

1 个答案:

答案 0 :(得分:1)

这是一个驱动程序错误。这里没有其他内容了。

可以读取和写入输出变量。这是GLSL的一部分。所以看起来驱动程序只是搞砸了它的实现。