如何有效地计算整个像素着色器阶段使用颜色的次数?

How to efficiently count the times that a color was used during whole Pixel Shader Stage?

我想在像素中实现它shader.Here是我代码的一部分:

首先,我创建一个 Texture1D 作为颜色 table

D3D11_TEXTURE1D_DESC t1d;
t1d.Width = ModelInfo::ColorCount;
t1d.ArraySize = 1;
t1d.MipLevels = 1;
t1d.CPUAccessFlags = 0;
t1d.MiscFlags = 0;
t1d.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
t1d.Usage = D3D11_USAGE_DEFAULT;
t1d.BindFlags = D3D11_BIND_SHADER_RESOURCE;

ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = ModelInfo::Colors;

hr = m_D3DDevice->CreateTexture1D(&t1d, &InitData, &m_ColorTable);
if (FAILED(hr))
    return hr;

D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
viewDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
viewDesc.Texture1D.MostDetailedMip = 0;
viewDesc.Texture1D.MipLevels = 1;
hr = m_D3DDevice->CreateShaderResourceView(m_ColorTable, &viewDesc, &m_ColorResView);
if (FAILED(hr))
    return hr;

然后我将它传递给像素着色器

m_ImmediateContext->PSSetShaderResources(0, 1, &m_ColorResView);

在像素着色器中,我使用这种颜色 table 是这样的:

Texture1D RandomTex : register(t0);

float4 PS(VS_OUTPUT Input, uint Primitive : SV_PrimitiveID) : SV_Target
{
    uint Index = Primitive % ColorCount.x;
    return RandomTex[Index];
}

我想使用这种颜色中每种颜色的 alpha 通道 table 来计算在整个像素着色器阶段使用了多少次颜色...

我想像代码一样在pixel shader中修改颜色table below.But 好像不行

RandomTex[Index].a = RandomTex[Index].a + 1;

我一直在寻找一种有效计算颜色的方法,而不是使用 C++ 在纹理上渲染颜色并计算 cpu。

我认为的所有方法都必须在 cpu 上做一些额外的计数工作,因为我发现除了我认为的那些方法之外,很难像 x++ 那样进行操作(可能是 gpu 上的一些并行问题)需要渲染纹理两次,这可能比直接计算 cpu 慢。

我正在深入研究它 time.But 没有 use.Please 帮助或尝试提供一些如何实现此目标的想法。

您可以将一个小的写入缓冲区附加到您的像素着色器(使用无序视图),并在像素着色器中使用原子操作。

这里是修改后的HLSL代码

Texture1D RandomTex : register(t0);

RWStructuredBuffer<uint> RWColorCountData : register(u1);

float4 PS(VS_OUTPUT Input, uint Primitive : SV_PrimitiveID) : SV_Target
{
    uint Index = Primitive % ColorCount.x;
    InterlockedAdd(RWColorCountData[Index], 1);
    return RandomTex[Index];
}

这里我使用了StructuredBuffer,但如果你愿意,你也可以使用ByteAddressBuffer。另请注意,资源已附加到寄存器 u1,因为第一个插槽仍由您的渲染目标占用。

您的写入缓冲区应具有与一维纹理相同的元素数,并且需要附加到管道(在渲染目标之上),OMSetRenderTargetsAndUnorderedAccessViews

每一帧,您还需要将缓冲区清除回 0(如果需要),否则值会随着时间增加,为此您可以使用 ClearUnorderedAccessViewUint

请注意,在您的情况下,由于您使用的是 uint 缓冲区并且该函数需要 UINT 值 [4],因此只有值 [0] 将用作清除值。