2
votes

I am thinking to achieve it in the pixel shader.Here is part of my code:

Firstly, I create a Texture1D as a color 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;

And then I pass it to the Pixel shader

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

In the pixel shader, i use this color table like this:

Texture1D RandomTex : register(t0);

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

I want to use the alpha channel of each color in this color table to count how many times the color used during whole Pixel Shader Stage...

I want to to modify the color table in the pixel shader just like the code below.But it seem to be infeasible.

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

I have been finding a way to count the color efficiently rather than render it on a texture and count in on cpu using c++.

All method I have thought has to do some extra counting work on cpu because I find it is hard to do the operation like x++(maybe some parallel problem on gpu),besides those method that I thought need to render the texture twice which might be slower that counting it on cpu straightly.

I am digging into it for a long time.But no use.Please help or try to give some ideas how to achieve this.

1
There is no way to change an input of a shader. You can only specify the output, but that would not work in your case. One option may be to render the indices to a special render target and then count the indices on the cpu, but that would not regard overdrawing.Gnietschow
@Gnietschow I intended to use the gpu to count the indices,thinking that may accelerate the counting process.For somehow,parallel problem,I find it is hard to do operation like x++(read the variable and then increase it)...frustrated :( .....BlauHimmel
If you want to write to a buffer from the pixel shader, you have to use an UAV. With an AtomicIncrement, you would be able to count what you want to count.galop1n

1 Answers

0
votes

You can attach a small write buffer to your pixel shader (with an unordered view), and use atomic operations in the pixel shader.

Here is the modified HLSL code

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];
}

Here I use a StructuredBuffer, but you can also use a ByteAddressBuffer if you prefer. Also note that resource is attached to register u1, as first slot is still taken by your render target.

Your write buffer should have the same element count as your 1d texture, and needs to be attached to the pipeline (on top of the render target), with OMSetRenderTargetsAndUnorderedAccessViews

Every frame, you will also need to clear your buffer back to 0 (if required), otherwise, values will increment over time, for this you can use ClearUnorderedAccessViewUint

Please note in your case, as you are using a uint buffer and the function expects UINT Values[4], only Values[0] will be used as clear value.