如何有效计算在整个Pixel Shader Stage中使用颜色的时间?

问题描述:

我想实现它在像素shader.Here是我的代码部分:如何有效计算在整个Pixel Shader Stage中使用颜色的时间?

首先,我创建了一个Texture1D作为色表

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);

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

Texture1D RandomTex : register(t0); 

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

我想用每一种颜色的alpha通道在此色表来算多少次全像素着色阶段过程中使用的颜色...

我想修改颜色表在像素着色器就像下面的代码一样。但它似乎是不可行的。

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

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

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

我正在挖掘它很长一段时间,但没有用。请帮助或尝试给一些想法如何实现这一点。

+0

无法更改着色器的输入。你只能指定输出,但这不适用于你的情况。 一个选项可能是将索引渲染到一个特殊的渲染目标,然后对CPU上的索引进行计数,但这不会考虑透支。 – Gnietschow

+0

@Gnietschow我打算使用GPU来计算指数,认为这可能会加速计数过程。对于某种方式来说,并行问题,我发现很难做像x ++这样的操作(读取变量然后增加它)...沮丧:(..... – BlauHimmel

+0

如果要从像素着色器写入缓冲区,则必须使用无人机。使用AtomicIncrement,您可以计算您想要计数的内容。 – galop1n

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

下面是修改的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,因为第一个插槽仍由您的渲染目标占用。

你写缓冲区应该有相同的元素算作你的1D纹理,并且需要连接到管道(上的渲染目标顶部),与OMSetRenderTargetsAndUnorderedAccessViews

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

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