I'm trying to implement Gaussian Filter using compute shader.
I have two texture resources. Firstly, I render entire scene to the first texture. Then I apply gaussian filter for this texture using compute shader( which writes results to the second texture). And finally, i use shader resource view of the second texture in final render pass (pixel shader just executes texture.Sample). But as result i just get black screen:(
Initialize textures and their resource views:
//Texture used for rendering
ID3D11Texture2D* renderTargetTexture;
ID3D11RenderTargetView* renderTargetTextureView;
ID3D11ShaderResourceView* shaderRenderTextureView;
//texture to which result of gaussian filter will be applied
ID3D11Texture2D* gaussTexture;
ID3D11UnorderedAccessView* gaussTextureUAView;
ID3D11ShaderResourceView* gaussTextureSRView;
ID3D11RenderTargetView* gaussTextureRTView;
/***** Create Texture Render Target View *****/
D3D11_TEXTURE2D_DESC textureDesc;
D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
//create render texture
ZeroMemory(&textureDesc, sizeof(D3D11_TEXTURE2D_DESC));
textureDesc.Width = textureWidth;
textureDesc.Height = textureHeight;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = 0;
textureDesc.MiscFlags = 0;
hr = d3d11Device->CreateTexture2D(&textureDesc, NULL, &renderTargetTexture);
if (FAILED(hr))
return false;
//create render target view
renderTargetViewDesc.Format = textureDesc.Format;
renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
renderTargetViewDesc.Texture2D.MipSlice = 0;
hr = d3d11Device->CreateRenderTargetView(renderTargetTexture, &renderTargetViewDesc, &renderTargetTextureView);
if (FAILED(hr))
return false;
//create shader resource view
shaderResourceViewDesc.Format = textureDesc.Format;
shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
shaderResourceViewDesc.Texture2D.MipLevels = 1;
hr = d3d11Device->CreateShaderResourceView(renderTargetTexture, &shaderResourceViewDesc, &shaderRenderTextureView);
if (FAILED(hr))
return false;
/*** GAUSSIAN TEXTURE ***/
D3D11_TEXTURE2D_DESC gtDesc;
D3D11_SHADER_RESOURCE_VIEW_DESC srView;
D3D11_UNORDERED_ACCESS_VIEW_DESC uaDesc;
D3D11_RENDER_TARGET_VIEW_DESC rtDesc;
//create gauss texture
ZeroMemory(&gtDesc, sizeof(gtDesc));
gtDesc.Width = textureWidth;
gtDesc.Height = textureHeight;
gtDesc.MipLevels = 1;
gtDesc.ArraySize = 1;
gtDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
gtDesc.SampleDesc.Count = 1;
gtDesc.Usage = D3D11_USAGE_DEFAULT;
gtDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
gtDesc.CPUAccessFlags = 0;
gtDesc.MiscFlags = 0;
hr = d3d11Device->CreateTexture2D(&gtDesc, NULL, &gaussTexture);
if (FAILED(hr))
return false;
//create render target view
rtDesc.Format = gtDesc.Format;
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtDesc.Texture2D.MipSlice = 0;
hr = d3d11Device->CreateRenderTargetView(gaussTexture, &rtDesc, &gaussTextureRTView);
if (FAILED(hr))
return false;
//create shader resource view
srView.Format = gtDesc.Format;
srView.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srView.Texture2D.MostDetailedMip = 0;
srView.Texture2D.MipLevels = 1;
hr = d3d11Device->CreateShaderResourceView(gaussTexture, &srView, &gaussTextureSRView);
if (FAILED(hr))
return false;
//create unordered access view
uaDesc.Format = gtDesc.Format;
uaDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
uaDesc.Texture2D.MipSlice = 0;
hr = d3d11Device->CreateUnorderedAccessView(gaussTexture, &uaDesc, &gaussTextureUAView);
if (FAILED(hr))
return false;
Now render entire scene to the first texture:
float bgTexColor[4] = {(1.0f, 0.0f, 0.0f, 1.0f)}; //default color is red!
d3d11DevCon->VSSetShader(VS, 0, 0);
d3d11DevCon->PSSetShader(PS, 0, 0);
d3d11DevCon->RSSetViewports(1, &texViewport);
d3d11DevCon->OMSetRenderTargets(1, &renderTargetTextureView, NULL);
d3d11DevCon->ClearRenderTargetView(renderTargetTextureView, bgTexColor);
d3d11DevCon->Draw(36, 0); //draw the cube
Apply gaussian filter:
d3d11DevCon->CSSetShader(CS, 0, 0);
d3d11DevCon->CSSetShaderResources(0, 1, &shaderRenderTextureView); //bind out rendered scene as shader resource view
d3d11DevCon->CSSetUnorderedAccessViews(0, 1, &gaussTextureUAView, NULL); //unordered access for resulting texture!
UINT x = (UINT)( ceil( textureWidth / 32.0f ) );
UINT y = (UINT)( ceil( textureHeight / 32.0f ) );
d3d11DevCon->Dispatch(x, y, 1);
Finally, render our final texture to the screen (in pixel shader i just use texture.Sample) :
d3d11DevCon->VSSetShader(textureVS, 0, 0);
d3d11DevCon->PSSetShader(texturePS, 0, 0);
d3d11DevCon->RSSetViewports(1, &viewport);
d3d11DevCon->OMSetRenderTargets(1, &renderTargetView, NULL); //back buffer now is render target
d3d11DevCon->PSSetShaderResources(0, 1, &gaussTextureSRView);
d3d11DevCon->Draw(6, 0);
Oh, by the way, here is my compute shader:
//Resources
Texture2D<float4> InputTex : register( t0 );
RWTexture2D<float4> OutputTex : register( u0 );
//filter kernel coefficients
static const float kernel[7][7] = {
0.000904706, 0.003157733, 0.00668492, 0.008583607, 0.00668492, 0.003157733, 0.000904706,
0.003157733, 0.01102157, 0.023332663, 0.029959733, 0.023332663, 0.01102157, 0.003157733,
0.00668492, 0.023332663, 0.049395249, 0.063424755, 0.049395249, 0.023332663, 0.00668492,
0.008583607, 0.029959733, 0.063424755, 0.081438997, 0.063424755, 0.029959733, 0.008583607,
0.00668492, 0.023332663, 0.049395249, 0.063424755, 0.049395249, 0.023332663, 0.00668492,
0.003157733, 0.01102157, 0.023332663, 0.029959733, 0.023332663, 0.01102157, 0.003157733,
0.000904706, 0.003157733, 0.00668492, 0.008583607, 0.00668492, 0.003157733, 0.000904706
};
[numthreads(32, 32, 1)]
void CS(uint3 DispatchThreadId : SV_DispatchThreadID)
{
//get coordinates of top left corner
int3 textureCoords = DispatchThreadId - int3(3, 3, 0);
//initialize final color
float4 finalColor = (float4)0.0f;
//loop through filter kernel getting final color
for (int i = 0; i < 7; i++)
for (int j = 0; j < 7; j++)
finalColor += InputTex.Load(textureCoords + int3(i, j, 0) ) * kernel[j];
//assign new color value to the output image
OutputTex[DispatchThreadId.xy] = finalColor;
//OutputTex[DispatchThreadId.xy] = float4(1.0f, 1.0f, 1.0f, 1.0f);
}
Why I think that the problem is with Unordered Access View? I tried to clear gaussTexture with red color after the compute shader has executed:
float bgTexColor[4] = {(1.0f, 0.0f, 0.0f, 1.0f)};
d3d11DevCon->ClearRenderTargetView(gaussTextureRTView, bgTexColor);
And i still get the black screen. But if I comment binding the unordered access to the compute shader I get what I should get - the red screen:
//d3d11DevCon->CSSetUnorderedAccessViews(0, 1, &gaussTextureUAView, NULL); //unordered access for resulting texture!
I'm pretty sure that compute shader itself works correctly as commenting Dispatch call without commenting CSSetUnorderedAccessViews still suffers the problem and I get only black screen.
Where the problem can be?
I would appreciate any help! Thanks in advance!