【问题标题】:Compute shader does not write to buffer?计算着色器不写入缓冲区?
【发布时间】:2018-07-26 03:42:38
【问题描述】:

我正在尝试对计算着色器进行剔除。 我的问题是我的原子计数器似乎没有被着色器写入,或者它确实被写入但随后被无效?

Renderdoc 说它没有数据,但 InstancesOut 中有值 (见下图)

这是我的计算着色器:

#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable

struct Indirect
{
    uint indexCount;
    uint instanceCount;
    uint firstIndex;
    uint vertexOffset;
    uint firstInstance;
};
struct Instance
{
    vec4 position;
};

layout (binding = 0, std430) buffer IndirectDraws
{
    Indirect indirects[];
};

layout (binding = 1) uniform UBO 
{
    vec4 frustum[6];
} ubo;

layout (binding = 2, std140) readonly buffer Instances
{
    Instance instances[];
};

layout (binding = 3, std140) writeonly buffer InstancesOut
{
    Instance instancesOut[];
};
layout (binding = 4) buffer Counter
{
    uint counter;
};

bool checkFrustrum(vec4 position, float radius)
{
    for(uint i = 0; i < 6; i++)
        if(dot(position, ubo.frustum[i]) + radius < 0.0)
            return false;
    return true;
}
layout (local_size_x = 1) in;
void main()
{
    uint i = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * gl_NumWorkGroups.x * gl_WorkGroupSize.x;

    uint instanceCount = 0;
    if(i == 0)
        atomicExchange(counter, 0);


    for(uint x = 0; x < indirects[i].instanceCount; x++)
    {
        vec4 position = instances[indirects[i].firstInstance + x].position;
        //if(checkFrustrum(position, 1.0))
        //{
            instancesOut[atomicAdd(counter, 1)].position = position;
            instanceCount++; 
        //}
    }
    //indirects[i].instanceCount = instanceCount;
    indirects[i].instanceCount = i; // testing
}

Picture of buffers in RenderDoc

感谢您的帮助!

【问题讨论】:

  • 您是否尝试在 atomicExchange 之后设置屏障。我担心在正确初始化计数器之前,着色器的其他调用会继续进行。
  • 我现在尝试使用障碍但得到相同的结果:(
  • 屏障();只在一个工作组内同步,因为他的工作组大小为 1,它什么也不做(local_size_x = 1)。

标签: c++ graphics glsl shader vulkan


【解决方案1】:

您似乎对同步和工作组的工作方式有误解。

在计算着色器中,原子将允许您跨工作组进行同步。但是,不能保证工作组执行的顺序,所以 atomicExchange(counter, 0);不保证在其他工作组执行之前发生。错误 #1?

工作组大小为 1 会极大地浪费资源,尤其是当您要承担跨工作组同步的费用时。工作组内的同步总是最快的,它允许您实际使用您的 gpu 资源(大多数 GPU 被组织成包含 SIMD 处理器的模块,这些处理器一次只能处理一个工作组上的执行。如果您只使用大小 1 工作组,这些处理器中有 31/32 或 63/64 处于空闲状态。{注意,大多数相同的处理器可以同时在内存中保存多个工作组,但在任何给定时刻只执行一个工作组})。此外,在工作组中,您可以将执行与障碍同步,确保操作顺序。错误 #2?

如果只添加一个,atomicCounterIncrement 可能是更好的指令。

在您的特定应用程序中,为什么instanceOut 的答案是错误的?在我看来实际上是正确的,每个输入都以输出结束,没有保证的顺序(因为你不能保证工作组以特定的顺序执行,即并行执行的工作方式)。如果您希望它们按顺序排列,请根据调用 ID 计算?

至于为什么renderDoc没有在计数器中显示值,我不知道,如果映射正确,它应该有一个值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多